<commit_before>var hotkeys = (function () {

var exports = {};

var pressed_keys = {};

function num_pressed_keys() {
    var size = 0, key;
    for (key in pressed_keys) {
        if (pressed_keys.hasOwnProperty(key))
            size++;
    }
    return size;
}

var directional_hotkeys = {
    40:  rows.next_visible,  // down arrow
    106: rows.next_visible,  // 'j'
    38:  rows.prev_visible,  // up arrow
    107: rows.prev_visible,  // 'k'
    36:  rows.first_visible, // Home
    35:  rows.last_visible   // End
};

var narrow_hotkeys = {
    115: narrow.by_recipient,  // 's'
    83:  narrow.by_subject,    // 'S'
    112: narrow.all_personals  // 'p'
};

// These are not exported, but we declare them here to make JSLint happy.
var process_key_in_input, process_compose_hotkey;

function simulate_keydown(keycode) {
    $(document).trigger($.Event('keydown', {keyCode: keycode}));
}

function process_hotkey(code) {
    var next_message;

    // Disable hotkeys on settings page etc.
    if (!$('#home').hasClass('active')) {
        return false;
    }

    // Disable hotkeys when in an input, textarea, or button
    if ($('input:focus,textarea:focus,button:focus').length > 0) {
        return process_key_in_input(code);
    }

    if (directional_hotkeys.hasOwnProperty(code)) {
        next_message = directional_hotkeys[code](selected_message);
        if (next_message.length !== 0) {
            select_message(next_message, {then_scroll: true});
        }
        if ((next_message.length === 0) && (code === 40 || code === 106)) {
            // At the last message, scroll to the bottom so we have
            // lots of nice whitespace for new messages coming in.
            //
            // FIXME: this doesn't work for End because rows.last_visible()
            // always returns a message.
            viewport.scrollTop($("#main_div").outerHeight(true));
        }
        return process_hotkey;
    }

    if (narrow_hotkeys.hasOwnProperty(code)) {
        narrow.target(selected_message_id);
        narrow_hotkeys[code]();
        return process_hotkey;
    }

    if (num_pressed_keys() > 1 &&
            // "shift"                        "caps lock"
            !((pressed_keys[16] === true || pressed_keys[20]) &&
                num_pressed_keys() === 2)) {
        // If you are already holding down another key, none of these
        // actions apply.
        return false;
    }

    switch (code) {
    case 33: // Page Up
        if (at_top_of_viewport()) {
            select_message(rows.first_visible(), {then_scroll: false});
        }
        return false; // We want the browser to actually page up and down
    case 32: // Spacebar
    case 34: // Page Down
        if (at_bottom_of_viewport()) {
            select_message(rows.last_visible(), {then_scroll: false});
        }
        return false;
    case 27: // Esc: cancel compose or un-narrow
        if (compose.composing()) {
            compose.cancel();
        } else {
            narrow.show_all_messages();
        }
        return process_hotkey;
    case 99: // 'c': compose
        compose.start('stream');
        return process_compose_hotkey;
    case 67: // 'C': compose huddle
        compose.start('personal');
        return process_compose_hotkey;
    case 114: // 'r': respond to message
        respond_to_message();
        return process_hotkey;
    case 82: // 'R': respond to author
        respond_to_message("personal");
        return process_hotkey;
    }

    return false;
}

/* The current handler function for keydown events.
   It should return a new handler, or 'false' to
   decline to handle the event. */
var keydown_handler = process_hotkey;

process_key_in_input = function (code) {
    if (code === 27) {
        // If the user hit the escape key, cancel the current compose
        compose.cancel();
    }
    // Otherwise, let the browser handle the key normally
    return false;
};

process_compose_hotkey = function (code) {
    if (code === 9) { // Tab: toggles between stream and huddle compose tabs.
        compose.toggle_mode();
        return process_compose_hotkey;
    }
    // Process the first non-tab character and everything after it
    // like any other keys typed in the input box
    keydown_handler = process_hotkey;
    return process_hotkey(code);
};

exports.set_compose = function () {
    keydown_handler = process_compose_hotkey;
};

$(document).keydown(function (e) {
    pressed_keys[e.which] = true;
});

$(document).keyup(function (e) {
    pressed_keys = {};
});

/* We register both a keydown and a keypress function because
   we want to intercept pgup/pgdn, escape, etc, and process them
   as they happen on the keyboard. However, if we processed
   letters/numbers in keydown, we wouldn't know what the case of
   the letters were.

   We want case-sensitive hotkeys (such as in the case of r vs R)
   so we bail in .keydown if the event is a letter or number and
   instead just let keypress go for it. */

$(document).keydown(function (event) {
    if (48 > event.which ||90 < event.which) { // outside the alphanumeric range
        var result = keydown_handler(event.which);
        if (typeof result === 'function') {
            keydown_handler = result;
            event.preventDefault();
        }
    }
});

$(document).keypress(function (event) {
    // What exactly triggers .keypress may vary by browser.
    // Welcome to compatability hell.
    //
    // In particular, when you press tab in Firefox, it fires a
    // keypress event with keycode 0 after processing the original
    // event.
    if (event.which !== 0 && event.charCode !== 0) {
        var result = keydown_handler(event.which);
        if (typeof result === 'function') {
            keydown_handler = result;
            event.preventDefault();
        }
    }
});

return exports;

}());
<commit_msg>Change 'p' hotkey to 'h', for 'huddles'<commit_after>var hotkeys = (function () {

var exports = {};

var pressed_keys = {};

function num_pressed_keys() {
    var size = 0, key;
    for (key in pressed_keys) {
        if (pressed_keys.hasOwnProperty(key))
            size++;
    }
    return size;
}

var directional_hotkeys = {
    40:  rows.next_visible,  // down arrow
    106: rows.next_visible,  // 'j'
    38:  rows.prev_visible,  // up arrow
    107: rows.prev_visible,  // 'k'
    36:  rows.first_visible, // Home
    35:  rows.last_visible   // End
};

var narrow_hotkeys = {
    115: narrow.by_recipient,  // 's'
    83:  narrow.by_subject,    // 'S'
    104: narrow.all_personals  // 'h'
};

// These are not exported, but we declare them here to make JSLint happy.
var process_key_in_input, process_compose_hotkey;

function simulate_keydown(keycode) {
    $(document).trigger($.Event('keydown', {keyCode: keycode}));
}

function process_hotkey(code) {
    var next_message;

    // Disable hotkeys on settings page etc.
    if (!$('#home').hasClass('active')) {
        return false;
    }

    // Disable hotkeys when in an input, textarea, or button
    if ($('input:focus,textarea:focus,button:focus').length > 0) {
        return process_key_in_input(code);
    }

    if (directional_hotkeys.hasOwnProperty(code)) {
        next_message = directional_hotkeys[code](selected_message);
        if (next_message.length !== 0) {
            select_message(next_message, {then_scroll: true});
        }
        if ((next_message.length === 0) && (code === 40 || code === 106)) {
            // At the last message, scroll to the bottom so we have
            // lots of nice whitespace for new messages coming in.
            //
            // FIXME: this doesn't work for End because rows.last_visible()
            // always returns a message.
            viewport.scrollTop($("#main_div").outerHeight(true));
        }
        return process_hotkey;
    }

    if (narrow_hotkeys.hasOwnProperty(code)) {
        narrow.target(selected_message_id);
        narrow_hotkeys[code]();
        return process_hotkey;
    }

    if (num_pressed_keys() > 1 &&
            // "shift"                        "caps lock"
            !((pressed_keys[16] === true || pressed_keys[20]) &&
                num_pressed_keys() === 2)) {
        // If you are already holding down another key, none of these
        // actions apply.
        return false;
    }

    switch (code) {
    case 33: // Page Up
        if (at_top_of_viewport()) {
            select_message(rows.first_visible(), {then_scroll: false});
        }
        return false; // We want the browser to actually page up and down
    case 32: // Spacebar
    case 34: // Page Down
        if (at_bottom_of_viewport()) {
            select_message(rows.last_visible(), {then_scroll: false});
        }
        return false;
    case 27: // Esc: cancel compose or un-narrow
        if (compose.composing()) {
            compose.cancel();
        } else {
            narrow.show_all_messages();
        }
        return process_hotkey;
    case 99: // 'c': compose
        compose.start('stream');
        return process_compose_hotkey;
    case 67: // 'C': compose huddle
        compose.start('personal');
        return process_compose_hotkey;
    case 114: // 'r': respond to message
        respond_to_message();
        return process_hotkey;
    case 82: // 'R': respond to author
        respond_to_message("personal");
        return process_hotkey;
    }

    return false;
}

/* The current handler function for keydown events.
   It should return a new handler, or 'false' to
   decline to handle the event. */
var keydown_handler = process_hotkey;

process_key_in_input = function (code) {
    if (code === 27) {
        // If the user hit the escape key, cancel the current compose
        compose.cancel();
    }
    // Otherwise, let the browser handle the key normally
    return false;
};

process_compose_hotkey = function (code) {
    if (code === 9) { // Tab: toggles between stream and huddle compose tabs.
        compose.toggle_mode();
        return process_compose_hotkey;
    }
    // Process the first non-tab character and everything after it
    // like any other keys typed in the input box
    keydown_handler = process_hotkey;
    return process_hotkey(code);
};

exports.set_compose = function () {
    keydown_handler = process_compose_hotkey;
};

$(document).keydown(function (e) {
    pressed_keys[e.which] = true;
});

$(document).keyup(function (e) {
    pressed_keys = {};
});

/* We register both a keydown and a keypress function because
   we want to intercept pgup/pgdn, escape, etc, and process them
   as they happen on the keyboard. However, if we processed
   letters/numbers in keydown, we wouldn't know what the case of
   the letters were.

   We want case-sensitive hotkeys (such as in the case of r vs R)
   so we bail in .keydown if the event is a letter or number and
   instead just let keypress go for it. */

$(document).keydown(function (event) {
    if (48 > event.which ||90 < event.which) { // outside the alphanumeric range
        var result = keydown_handler(event.which);
        if (typeof result === 'function') {
            keydown_handler = result;
            event.preventDefault();
        }
    }
});

$(document).keypress(function (event) {
    // What exactly triggers .keypress may vary by browser.
    // Welcome to compatability hell.
    //
    // In particular, when you press tab in Firefox, it fires a
    // keypress event with keycode 0 after processing the original
    // event.
    if (event.which !== 0 && event.charCode !== 0) {
        var result = keydown_handler(event.which);
        if (typeof result === 'function') {
            keydown_handler = result;
            event.preventDefault();
        }
    }
});

return exports;

}());
<|endoftext|>


<commit_before>/* jshint node:true, camelcase:false */
var gulp = require('gulp');
var browserSync = require('browser-sync');
var pkg = require('./package.json');
var plug = require('gulp-load-plugins')();

var reload = browserSync.reload;

var colors = plug.util.colors;
var env = plug.util.env;
var log = plug.util.log;
var port = 7999;

gulp.task('help', plug.taskListing);

/**
 * serve the dev environment
 */
gulp.task('serve-dev', function() {
    serve({mode: 'dev'});
    startBrowserSync();
});

function serve(args) {
    var options = {
        script: 'server/server.js',
//        delayTime: 1,
        ext: 'html js',
        env: {
            'NODE_ENV': args.mode,
            'PORT': port
        },
        watch: ['./server/']
    };

    if (args.debug) {
        require('child_process').exec('node-inspector');
        options.nodeArgs = [args.debug + '=5858'];
    }

    log('Starting MongoDB');
    require('child_process').exec('mongod --dbpath db/zza-mongo-database');

    return plug.nodemon(options)
        .on('start', function() {
            //startBrowserSync();
        })
        .on('restart', function() {
            log('restarted browser-sync!');
            setTimeout(function () {
              //  browserSync.reload({stream: false});
            }, 1000);
        });
}

/**
 * Start BrowserSync
 */
function startBrowserSync() {
//    if (browserSync.active) {
//        return;
//    }

    log('Starting BrowserSync on port 3000');
    browserSync({
        proxy: 'localhost:' + port,
        port: 3000,
        files: './client/app/**/*.*',
        ghostMode: { // these are the defaults t,f,t,t
            clicks: true,
            location: false,
            forms: true,
            scroll: true
        },
        logLevel: 'debug',
        logPrefix: 'zza',
        notify: true,
        reloadDelay: 1000
    });
}
<commit_msg>uncommented gulp sync code<commit_after>/* jshint node:true, camelcase:false */
var gulp = require('gulp');
var browserSync = require('browser-sync');
var pkg = require('./package.json');
var plug = require('gulp-load-plugins')();

var reload = browserSync.reload;

var colors = plug.util.colors;
var env = plug.util.env;
var log = plug.util.log;
var port = 7999;

gulp.task('help', plug.taskListing);

/**
 * serve the dev environment
 */
gulp.task('serve-dev', function() {
    serve({mode: 'dev'});
    startBrowserSync();
});

function serve(args) {
    var options = {
        script: 'server/server.js',
        delayTime: 1,
        ext: 'html js',
        env: {
            'NODE_ENV': args.mode,
            'PORT': port
        },
        watch: ['./server/']
    };

    if (args.debug) {
        require('child_process').exec('node-inspector');
        options.nodeArgs = [args.debug + '=5858'];
    }

    log('Starting MongoDB');
    require('child_process').exec('mongod --dbpath db/zza-mongo-database');

    return plug.nodemon(options)
        .on('start', function() {
            startBrowserSync();
        })
        .on('restart', function() {
            log('restarted browser-sync!');
            setTimeout(function () {
                browserSync.reload({stream: false});
            }, 1000);
        });
}

/**
 * Start BrowserSync
 */
function startBrowserSync() {
    if (browserSync.active) {
        return;
    }

    log('Starting BrowserSync on port 3000');
    browserSync({
        proxy: 'localhost:' + port,
        port: 3000,
        files: './client/app/**/*.*',
        ghostMode: { // these are the defaults t,f,t,t
            clicks: true,
            location: false,
            forms: true,
            scroll: true
        },
        logLevel: 'debug',
        logPrefix: 'zza',
        notify: true,
        reloadDelay: 1000
    });
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011  JTalks.org Team
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

/** Namespace for this file */
var CodeHighlighting = {}

CodeHighlighting.ADD_COMMENT_FORM_ID = 'add-comment-form';

/** ID of branch where we currently are */
CodeHighlighting.branchId = 0;
/** ID of current user */
CodeHighlighting.currentUserId = 0;
/** Indicates if current user has EDIT_OWN_POSTS permission */
CodeHighlighting.canEditOwnPosts = false;
/** Indicates if current user has EDIT_OTHERS_POSTS permission */
CodeHighlighting.canEditOtherPosts = false;
/** Indicates if current user has DELETE_OWN_POSTS permission */
CodeHighlighting.canDeleteOwnPosts = false;
/** Indicates if current user has DELETE_OTHERS_POSTS permission */
CodeHighlighting.canDeleteOtherPosts = false;

/**
 * Called when document rendering is completed. Highlight code and
 * sets up handlers for code review if needed.
 */
$(document).ready(function () {
    prettyPrint(function () {
        var hasCodeReview = $('#has-code-review').val();
        if (hasCodeReview == 'true') {
        	CodeHighlighting.initializeVariables();
            CodeHighlighting.displayReviewComments();
			CodeHighlighting.setupGeneralHandlers();

            var branchId = $('#branchId').val();
            PermissionService.hasPermission(branchId, 'BRANCH',
                    'BranchPermission.LEAVE_COMMENTS_IN_CODE_REVIEW',
                    CodeHighlighting.setupAddCommentFormHandlers);

			CodeHighlighting.setupEditCommentHandlers();
        }
    });
});

/**
 * Function to append comment to HTML
 */
CodeHighlighting.addComment = function (comment) {
    $('.script-first-post ol.linenums li:nth-child(' + comment.lineNumber + ')')
			.append(CodeHighlighting.getCommentHtml(comment));
}

/**
 * Function to update existing comment. Actually removes existing comment and adds new.
 */
CodeHighlighting.updateComment = function (comment) {
    var reviewContainer = $('.script-first-post .review-container input[name=id][value=' + comment.id + ']').parent();
	reviewContainer.after(CodeHighlighting.getCommentHtml(comment));
	reviewContainer.remove();
}

/**
 * Get review comments for this topic from server and display them
 * @return deffered object for AJAX request (displaying comments)
 */
CodeHighlighting.displayReviewComments = function () {
    var codeReviewId = $('#codeReviewId').val();
    return $.ajax({
        url: baseUrl + '/reviews/' + codeReviewId + '/json',
        type: "GET",
        success: function (data) {
            var comments = data.result.comments;
            for (var i = 0; i < comments.length; i++) {
                CodeHighlighting.addComment(comments[i]);
            }
        },
        error: function () {
            bootbox.alert($labelUnexpectedError);
        }
    });
}

/**
 * Initialize variables used in this scope.
 */
CodeHighlighting.initializeVariables = function() {
	CodeHighlighting.branchId = $('#branchId').val();
	CodeHighlighting.currentUserId = $('#userId').val();
	CodeHighlighting.canEditOwnPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
	                'BranchPermission.EDIT_OWN_POSTS');
	CodeHighlighting.canEditOtherPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
	                'BranchPermission.EDIT_OTHERS_POSTS');
    CodeHighlighting.canDeleteOwnPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
        'BranchPermission.DELETE_OWN_POSTS');
    CodeHighlighting.canDeleteOtherPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
        'BranchPermission.DELETE_OTHERS_POSTS');
}

CodeHighlighting.setupGeneralHandlers = function() {
	// handle links even if they are located on the comment's div (clicks on which we don't handle
	$('.script-first-post').on('click', 'ol.linenums li .review-header a', function () {
		window.location = $(this).attr('href');
	});
}

/**
 * Initializes handlers for 'Add comment' action
 */
CodeHighlighting.setupAddCommentFormHandlers = function () {
    $('.script-first-post').on('click', 'input:button[name=cancel-add]', function (event) {
        event.stopPropagation();
        CodeHighlighting.removeCommentForm();
    });

	// don't handle clicks on comments
	$('.script-first-post').on('click', 'ol.linenums li div.review-container', function () {
		return false;
	});

    $('.script-first-post').on('click', 'ol.linenums li', function () {
        var addCommentForm = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
        if (addCommentForm.length == 0) {
            var index = $(this).index();
			// display form before first comment
			CodeHighlighting.showAddCommentForm($(this).find('span:last'), index + 1);
        }

    });

    $('.script-first-post').on('click', "input:button[name=add]", function (event) {
        event.stopPropagation();

        var formContainer = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
        if (Antimultipost.beingSubmitted(formContainer)) {
            return;
        }
        Antimultipost.disableSubmit(formContainer);

		var data = {id: 0, authorId:0, authorUsername:""};
        data.lineNumber = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=lineNumber]').val();
        data.body = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=body]').val();
		data.reviewId = $('#codeReviewId').val();

        $.post(baseUrl + '/reviewcomments/new', data)
                .success(function (data) {
                    if (data.status == 'SUCCESS') {
                        CodeHighlighting.removeCommentForm();
						CodeHighlighting.addComment(data.result)
                    } else if (data.reason == 'VALIDATION') {
                        CodeHighlighting.displayValidationErrors(data.result);
                    } else if (data.reason == 'SECURITY'){
                    	bootbox.alert($labelYouDontHavePermissions);
                    } else if (data.reason == 'ENTITY_NOT_FOUND') {
                    	bootbox.alert($labelTopicWasRemoved);
                    } else {
                        bootbox.alert($labelUnexpectedError);
                    }
                })
                .error(function (data) {
                    bootbox.alert($label.topicWasRemovedOrYouDontHavePermissions);
                })
                .complete(function () {
                    Antimultipost.enableSubmit(formContainer);
                });
    });
}

/**
 * Initializes handlers for 'Edit comment' actions
 */
CodeHighlighting.setupEditCommentHandlers = function() {
    $('.script-first-post').on('click', 'input:button[name=cancel-edit]', function (event) {
        event.stopPropagation();
		$('#' + CodeHighlighting.ADD_COMMENT_FORM_ID).prev().show();
        CodeHighlighting.removeCommentForm();
    });

	$('.script-first-post').on('click', 'div.review-container a[name=edit-review]', function() {
		var addCommentForm = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
		if (addCommentForm.length == 0) {
			var reviewContainer = $(this).closest('.review-container');
			var comment = {};
			comment.id = reviewContainer.find('input[name=id]').val();
			comment.body = reviewContainer.find('.review-body').html();
			CodeHighlighting.showEditCommentForm(reviewContainer, comment);
        }

		return false;
	});

    var deleteComment = function (elementForDeleting, reviewId, commentId) {
        $.ajax({
            url:baseUrl + '/reviewcomments/delete?reviewId=' + reviewId + '&commentId=' + commentId,
            type:"GET",
            success:function (data) {
                $(elementForDeleting).remove();
            },
            error:function () {
                bootbox.alert($labelUnexpectedError);
            }
        });
    };

    $('div.review-container').each(function () {
        var commentId = this.find('input[name=id]').val();
        var reviewId = $('input[id="codeReviewId"]').val();
        this.on('click', 'a[name="delete-review"]', deleteComment(this, reviewId, commentId));
        return false;
    });

	$('.script-first-post').on('click', "input:button[name=edit]", function (event) {
        event.stopPropagation();

        var formContainer = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
        if (Antimultipost.beingSubmitted(formContainer)) {
            return;
        }
        Antimultipost.disableSubmit(formContainer);

		var data = {authorId:0, authorUsername:""};
		data.id = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=id]').val();
        data.lineNumber = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=lineNumber]').val();
        data.body = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=body]').val();
		data.branchId = $('#branchId').val();

        $.post(baseUrl + '/reviewcomments/edit', data)
                .success(function (data) {
                    if (data.status == 'SUCCESS') {
						CodeHighlighting.updateComment(data.result);
						CodeHighlighting.removeCommentForm();
                    } else if (data.reason == 'VALIDATION') {
                        CodeHighlighting.displayValidationErrors(data.result);
                    } else if (data.reason == 'SECURITY'){
                    	bootbox.alert($labelYouDontHavePermissions);
                    } else if (data.reason == 'ENTITY_NOT_FOUND') {
                    	bootbox.alert($labelTopicWasRemoved);
                    } else {
                        bootbox.alert($labelUnexpectedError);
                    }
                })
                .error(function (data) {
                    bootbox.alert($labelUnexpectedError);
                })
                .complete(function () {
                    Antimultipost.enableSubmit(formContainer);
                });
    });
}

/**
 * Build HTML piece for review comment
 * @param comment code review comment
 * @return div (string) with comment data
 */
CodeHighlighting.getCommentHtml = function (comment) {
	var editButtonHtml = '';
    var deleteButtonHtml = '';
	if (CodeHighlighting.canEditOtherPosts
			|| (CodeHighlighting.currentUserId == comment.authorId
					&& CodeHighlighting.canEditOwnPosts)) {
		editButtonHtml = '' + $labelEdit + '';
	}
    if (CodeHighlighting.canDeleteOtherPosts
        || (CodeHighlighting.currentUserId == comment.authorId
        && CodeHighlighting.canDeleteOwnPosts)) {
        deleteButtonHtml = '' + $labelDelete + '';
    }
    var result =
            '
 '
				+ '<input type=hidden name=id value="' + comment.id + '"/>'
				+ '<input type=hidden name=authorId value="' + comment.authorId + '"/>'
                + '
'
                    + ''
                + '
'
                + '
'
				    + '
'
				    	+ editButtonHtml
                        +' '
                        + deleteButtonHtml
				    + '
'
                    + '
'
						+ '' + CodeHighlighting.htmlEncode(comment.authorUsername) + ''
						+ ' ' + $labelReviewSays + ': '
                    + '
'
                    + '
'
						+ CodeHighlighting.htmlEncode(comment.body)
                    + '
'
                + '
'
            + '
';
    return result;
}

/**
 * Build HTML piece for add comment form
 * @param submitButtonTitle title of submit button
 * @param action name of action (name being added to button names)
 * @param lineNumber number of line where form will be placed
 * @param comment data to fill form if defined
 * @return string with HTML piece for the form
 */
CodeHighlighting.getCommentForm = function (submitButtonTitle, action, lineNumber, comment) {
    if (comment === undefined) {
		comment = {id:0,body:''};
	}
    var result =
            '
'
                + '
'
                    + '<input type=hidden name=lineNumber value="' + lineNumber + '"/>'
					+ '<input type=hidden name=id value="' + comment.id + '"/>'
                    + '<textarea name="body" class="review-container-content">' + comment.body + '</textarea>'
                + '
'
                + '
'
                    + '<input type=button name="' + action + '" value="' + submitButtonTitle + '" class="btn btn-primary review-container-controls-ok"/>'
                    + '<input type=button name=cancel-' + action + ' value="' + $labelCancel + '" class="btn review-container-controls-cancel"/>'
                + '
'
                + '' + $labelKeymapsReview + ''
            + '
';
    return result;
}

/**
 * Show comment form below given element
 * @param element jquery element after which show form
 * @param submitButtonTitle title of submit button
 * @param submitButtonName name of submit button element
 * @param lineNumber number of line where form will be placed
 * @param comment data to fill form if defined
 */
CodeHighlighting.showCommentForm = function(element, submitButtonTitle, submitButtonName, lineNumber, comment) {
	element.after(CodeHighlighting.getCommentForm(submitButtonTitle, submitButtonName, lineNumber, comment));
	var reviewContent = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' textarea');
    reviewContent.keydown(Keymaps.review);
    reviewContent.focus();
}

/**
 * Show 'add comment' form below given element
 * @param element jquery element after which show form
 * @param lineNumber number of line where form will be placed
 */
CodeHighlighting.showAddCommentForm = function(element, lineNumber) {
	CodeHighlighting.showCommentForm(element, $labelAdd, 'add', lineNumber);
}

/**
 * Show 'edit comment' form at the location of given element. Element will
 * be hide from the document.
 * @param element jquery element after which show form
 * @param comment data to fill form
 */
CodeHighlighting.showEditCommentForm = function(element, comment) {
	CodeHighlighting.showCommentForm(element, $labelEdit, 'edit', 0, comment);
	element.hide();
}

/**
 * Remove comment form from the page
 */
CodeHighlighting.removeCommentForm = function () {
    $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID).remove();
}

/**
 * Display error messages
 *
 * @param errors list or errors
 */
CodeHighlighting.displayValidationErrors = function (errors) {
    $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' span.help-inline').remove();

    if (errors.length > 0) {
        var currentControlGroup = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=body]').parent();
        currentControlGroup.addClass("error");
        currentControlGroup.append('');

        var errorsContainer = currentControlGroup.find('span.help-inline');
        for (var i = 0; i < errors.length; i++) {
            errorsContainer.append(errors[i].message + '
');
        }
    }
}

/**
 * Encodes given string by escaping special HTML characters
 *
 * @param s string to be encoded
 */
CodeHighlighting.htmlEncode = function(s)
{
  var el = document.createElement("div");
  el.innerText = el.textContent = s;
  s = el.innerHTML;
  return s;
}<commit_msg>#JC-1201 Added view script implementation<commit_after>/*
 * Copyright (C) 2011  JTalks.org Team
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

/** Namespace for this file */
var CodeHighlighting = {}

CodeHighlighting.ADD_COMMENT_FORM_ID = 'add-comment-form';

/** ID of branch where we currently are */
CodeHighlighting.branchId = 0;
/** ID of current user */
CodeHighlighting.currentUserId = 0;
/** Indicates if current user has EDIT_OWN_POSTS permission */
CodeHighlighting.canEditOwnPosts = false;
/** Indicates if current user has EDIT_OTHERS_POSTS permission */
CodeHighlighting.canEditOtherPosts = false;
/** Indicates if current user has DELETE_OWN_POSTS permission */
CodeHighlighting.canDeleteOwnPosts = false;
/** Indicates if current user has DELETE_OTHERS_POSTS permission */
CodeHighlighting.canDeleteOtherPosts = false;

/**
 * Called when document rendering is completed. Highlight code and
 * sets up handlers for code review if needed.
 */
$(document).ready(function () {
    prettyPrint(function () {
        var hasCodeReview = $('#has-code-review').val();
        if (hasCodeReview == 'true') {
        	CodeHighlighting.initializeVariables();
            CodeHighlighting.displayReviewComments();
			CodeHighlighting.setupGeneralHandlers();

            var branchId = $('#branchId').val();
            PermissionService.hasPermission(branchId, 'BRANCH',
                    'BranchPermission.LEAVE_COMMENTS_IN_CODE_REVIEW',
                    CodeHighlighting.setupAddCommentFormHandlers);

			CodeHighlighting.setupEditCommentHandlers();
        }
    });
});

/**
 * Function to append comment to HTML
 */
CodeHighlighting.addComment = function (comment) {
    $('.script-first-post ol.linenums li:nth-child(' + comment.lineNumber + ')')
			.append(CodeHighlighting.getCommentHtml(comment));
}

/**
 * Function to update existing comment. Actually removes existing comment and adds new.
 */
CodeHighlighting.updateComment = function (comment) {
    var reviewContainer = $('.script-first-post .review-container input[name=id][value=' + comment.id + ']').parent();
	reviewContainer.after(CodeHighlighting.getCommentHtml(comment));
	reviewContainer.remove();
}

/**
 * Get review comments for this topic from server and display them
 * @return deffered object for AJAX request (displaying comments)
 */
CodeHighlighting.displayReviewComments = function () {
    var codeReviewId = $('#codeReviewId').val();
    return $.ajax({
        url: baseUrl + '/reviews/' + codeReviewId + '/json',
        type: "GET",
        success: function (data) {
            var comments = data.result.comments;
            for (var i = 0; i < comments.length; i++) {
                CodeHighlighting.addComment(comments[i]);
            }
        },
        error: function () {
            bootbox.alert($labelUnexpectedError);
        }
    });
}

/**
 * Initialize variables used in this scope.
 */
CodeHighlighting.initializeVariables = function() {
	CodeHighlighting.branchId = $('#branchId').val();
	CodeHighlighting.currentUserId = $('#userId').val();
	CodeHighlighting.canEditOwnPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
	                'BranchPermission.EDIT_OWN_POSTS');
	CodeHighlighting.canEditOtherPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
	                'BranchPermission.EDIT_OTHERS_POSTS');
    CodeHighlighting.canDeleteOwnPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
        'BranchPermission.DELETE_OWN_POSTS');
    CodeHighlighting.canDeleteOtherPosts = PermissionService.getHasPermission(CodeHighlighting.branchId, 'BRANCH',
        'BranchPermission.DELETE_OTHERS_POSTS');
}

CodeHighlighting.setupGeneralHandlers = function() {
	// handle links even if they are located on the comment's div (clicks on which we don't handle
	$('.script-first-post').on('click', 'ol.linenums li .review-header a', function () {
		window.location = $(this).attr('href');
	});
}

/**
 * Initializes handlers for 'Add comment' action
 */
CodeHighlighting.setupAddCommentFormHandlers = function () {
    $('.script-first-post').on('click', 'input:button[name=cancel-add]', function (event) {
        event.stopPropagation();
        CodeHighlighting.removeCommentForm();
    });

	// don't handle clicks on comments
	$('.script-first-post').on('click', 'ol.linenums li div.review-container', function () {
		return false;
	});

    $('.script-first-post').on('click', 'ol.linenums li', function () {
        var addCommentForm = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
        if (addCommentForm.length == 0) {
            var index = $(this).index();
			// display form before first comment
			CodeHighlighting.showAddCommentForm($(this).find('span:last'), index + 1);
        }

    });

    $('.script-first-post').on('click', "input:button[name=add]", function (event) {
        event.stopPropagation();

        var formContainer = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
        if (Antimultipost.beingSubmitted(formContainer)) {
            return;
        }
        Antimultipost.disableSubmit(formContainer);

		var data = {id: 0, authorId:0, authorUsername:""};
        data.lineNumber = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=lineNumber]').val();
        data.body = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=body]').val();
		data.reviewId = $('#codeReviewId').val();

        $.post(baseUrl + '/reviewcomments/new', data)
                .success(function (data) {
                    if (data.status == 'SUCCESS') {
                        CodeHighlighting.removeCommentForm();
						CodeHighlighting.addComment(data.result)
                    } else if (data.reason == 'VALIDATION') {
                        CodeHighlighting.displayValidationErrors(data.result);
                    } else if (data.reason == 'SECURITY'){
                    	bootbox.alert($labelYouDontHavePermissions);
                    } else if (data.reason == 'ENTITY_NOT_FOUND') {
                    	bootbox.alert($labelTopicWasRemoved);
                    } else {
                        bootbox.alert($labelUnexpectedError);
                    }
                })
                .error(function (data) {
                    bootbox.alert($label.topicWasRemovedOrYouDontHavePermissions);
                })
                .complete(function () {
                    Antimultipost.enableSubmit(formContainer);
                });
    });
}

/**
 * Initializes handlers for 'Edit comment' actions
 */
CodeHighlighting.setupEditCommentHandlers = function() {
    $('.script-first-post').on('click', 'input:button[name=cancel-edit]', function (event) {
        event.stopPropagation();
		$('#' + CodeHighlighting.ADD_COMMENT_FORM_ID).prev().show();
        CodeHighlighting.removeCommentForm();
    });

	$('.script-first-post').on('click', 'div.review-container a[name=edit-review]', function() {
		var addCommentForm = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
		if (addCommentForm.length == 0) {
			var reviewContainer = $(this).closest('.review-container');
			var comment = {};
			comment.id = reviewContainer.find('input[name=id]').val();
			comment.body = reviewContainer.find('.review-body').html();
			CodeHighlighting.showEditCommentForm(reviewContainer, comment);
        }

		return false;
	});

    $('.script-first-post').on('click', 'div.review-container a[name=delete-review]', function () {
        var reviewContainer = $(this).closest('.review-container');
        var commentId = reviewContainer.find('input[name=id]').val();
        var reviewId = $('input[id="codeReviewId"]').val();
        $.ajax({
            url:baseUrl + '/reviewcomments/delete?reviewId=' + reviewId + '&commentId=' + commentId,
            type:"GET",
            success:function () {
                $(reviewContainer).remove();
            },
            error:function () {
                bootbox.alert($labelUnexpectedError);
            }
        });

        return false;
    });

	$('.script-first-post').on('click', "input:button[name=edit]", function (event) {
        event.stopPropagation();

        var formContainer = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID);
        if (Antimultipost.beingSubmitted(formContainer)) {
            return;
        }
        Antimultipost.disableSubmit(formContainer);

		var data = {authorId:0, authorUsername:""};
		data.id = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=id]').val();
        data.lineNumber = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=lineNumber]').val();
        data.body = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=body]').val();
		data.branchId = $('#branchId').val();

        $.post(baseUrl + '/reviewcomments/edit', data)
                .success(function (data) {
                    if (data.status == 'SUCCESS') {
						CodeHighlighting.updateComment(data.result);
						CodeHighlighting.removeCommentForm();
                    } else if (data.reason == 'VALIDATION') {
                        CodeHighlighting.displayValidationErrors(data.result);
                    } else if (data.reason == 'SECURITY'){
                    	bootbox.alert($labelYouDontHavePermissions);
                    } else if (data.reason == 'ENTITY_NOT_FOUND') {
                    	bootbox.alert($labelTopicWasRemoved);
                    } else {
                        bootbox.alert($labelUnexpectedError);
                    }
                })
                .error(function (data) {
                    bootbox.alert($labelUnexpectedError);
                })
                .complete(function () {
                    Antimultipost.enableSubmit(formContainer);
                });
    });
}

/**
 * Build HTML piece for review comment
 * @param comment code review comment
 * @return div (string) with comment data
 */
CodeHighlighting.getCommentHtml = function (comment) {
	var editButtonHtml = '';
    var deleteButtonHtml = '';
	if (CodeHighlighting.canEditOtherPosts
			|| (CodeHighlighting.currentUserId == comment.authorId
					&& CodeHighlighting.canEditOwnPosts)) {
		editButtonHtml = '' + $labelEdit + '';
	}
    if (CodeHighlighting.canDeleteOtherPosts
        || (CodeHighlighting.currentUserId == comment.authorId
        && CodeHighlighting.canDeleteOwnPosts)) {
        deleteButtonHtml = '' + $labelDelete + '';
    }
    var result =
            '
 '
				+ '<input type=hidden name=id value="' + comment.id + '"/>'
				+ '<input type=hidden name=authorId value="' + comment.authorId + '"/>'
                + '
'
                    + ''
                + '
'
                + '
'
				    + '
'
				    	+ editButtonHtml
                        +' '
                        + deleteButtonHtml
				    + '
'
                    + '
'
						+ '' + CodeHighlighting.htmlEncode(comment.authorUsername) + ''
						+ ' ' + $labelReviewSays + ': '
                    + '
'
                    + '
'
						+ CodeHighlighting.htmlEncode(comment.body)
                    + '
'
                + '
'
            + '
';
    return result;
}

/**
 * Build HTML piece for add comment form
 * @param submitButtonTitle title of submit button
 * @param action name of action (name being added to button names)
 * @param lineNumber number of line where form will be placed
 * @param comment data to fill form if defined
 * @return string with HTML piece for the form
 */
CodeHighlighting.getCommentForm = function (submitButtonTitle, action, lineNumber, comment) {
    if (comment === undefined) {
		comment = {id:0,body:''};
	}
    var result =
            '
'
                + '
'
                    + '<input type=hidden name=lineNumber value="' + lineNumber + '"/>'
					+ '<input type=hidden name=id value="' + comment.id + '"/>'
                    + '<textarea name="body" class="review-container-content">' + comment.body + '</textarea>'
                + '
'
                + '
'
                    + '<input type=button name="' + action + '" value="' + submitButtonTitle + '" class="btn btn-primary review-container-controls-ok"/>'
                    + '<input type=button name=cancel-' + action + ' value="' + $labelCancel + '" class="btn review-container-controls-cancel"/>'
                + '
'
                + '' + $labelKeymapsReview + ''
            + '
';
    return result;
}

/**
 * Show comment form below given element
 * @param element jquery element after which show form
 * @param submitButtonTitle title of submit button
 * @param submitButtonName name of submit button element
 * @param lineNumber number of line where form will be placed
 * @param comment data to fill form if defined
 */
CodeHighlighting.showCommentForm = function(element, submitButtonTitle, submitButtonName, lineNumber, comment) {
	element.after(CodeHighlighting.getCommentForm(submitButtonTitle, submitButtonName, lineNumber, comment));
	var reviewContent = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' textarea');
    reviewContent.keydown(Keymaps.review);
    reviewContent.focus();
}

/**
 * Show 'add comment' form below given element
 * @param element jquery element after which show form
 * @param lineNumber number of line where form will be placed
 */
CodeHighlighting.showAddCommentForm = function(element, lineNumber) {
	CodeHighlighting.showCommentForm(element, $labelAdd, 'add', lineNumber);
}

/**
 * Show 'edit comment' form at the location of given element. Element will
 * be hide from the document.
 * @param element jquery element after which show form
 * @param comment data to fill form
 */
CodeHighlighting.showEditCommentForm = function(element, comment) {
	CodeHighlighting.showCommentForm(element, $labelEdit, 'edit', 0, comment);
	element.hide();
}

/**
 * Remove comment form from the page
 */
CodeHighlighting.removeCommentForm = function () {
    $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID).remove();
}

/**
 * Display error messages
 *
 * @param errors list or errors
 */
CodeHighlighting.displayValidationErrors = function (errors) {
    $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' span.help-inline').remove();

    if (errors.length > 0) {
        var currentControlGroup = $('#' + CodeHighlighting.ADD_COMMENT_FORM_ID + ' [name=body]').parent();
        currentControlGroup.addClass("error");
        currentControlGroup.append('');

        var errorsContainer = currentControlGroup.find('span.help-inline');
        for (var i = 0; i < errors.length; i++) {
            errorsContainer.append(errors[i].message + '
');
        }
    }
}

/**
 * Encodes given string by escaping special HTML characters
 *
 * @param s string to be encoded
 */
CodeHighlighting.htmlEncode = function(s)
{
  var el = document.createElement("div");
  el.innerText = el.textContent = s;
  s = el.innerHTML;
  return s;
}<|endoftext|>


<commit_before>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Shopware_Config
 * @subpackage Config
 * @version    $Id$
 * @author shopware AG
 */

/**
 * todo@all: Documentation
 */
//{block name="backend/config/model/form/shop"}
Ext.define('Shopware.apps.Config.model.form.Shop', {
    extend:'Ext.data.Model',

    fields: [
		//{block name="backend/config/model/form/shop/fields"}{/block}
        { name: 'id', type:'int', useNull: true, defaultValue: null },
        { name: 'typeSwitch',  persist: false, convert: function(v, record) {

            // The default value determines if a newly created shop is either a subshop (sub) or a language shop (lang).
            // record.phantom is set automatically on new, unsaved records by ExtJs.
            //{block name="backend/config/model/form/shop/fields/typeSwitch/defaultValue"}
            if(record.phantom){
                return 'lang';
            }
            //{/block}

            // The shop type is internally determined by the presence/absence of the mainId
            return record.raw && record.raw.main && record.raw.main.id ? 'lang' : 'sub';
        }},
        { name: 'name', type: 'string' },
        { name: 'title', type: 'string', useNull: true },
        { name: 'position', type: 'int' },
        { name: 'name', type: 'string' },
        { name: 'default', type: 'boolean', defaultValue: false },
        { name: 'active', type: 'boolean', defaultValue: true },
        { name: 'host', type: 'string', useNull: true },
        { name: 'basePath', type: 'string', useNull: true },
        { name: 'baseUrl', type: 'string', useNull: true },
        { name: 'secure', type: 'boolean' },
        { name: 'alwaysSecure', type: 'boolean' },
        { name: 'secureHost', type: 'string', useNull: true },
        { name: 'secureBasePath', type: 'string', useNull: true },
        { name: 'hosts', type: 'string', useNull: true },
        { name: 'customerScope', type: 'boolean' },

        // Use "convert" because "mappping" not working with "useNull"
        { name: 'mainId', convert: function(v, record) {
            return v || record.raw && record.raw.main && record.raw.main.id;
        }, useNull: true, defaultValue: null },
        { name: 'localeId', convert: function(v, record) {
            return v || record.raw && record.raw.locale && record.raw.locale.id;
        }, useNull: true },
        { name: 'currencyId', convert: function(v, record) {
            return v || record.raw && record.raw.currency && record.raw.currency.id;
        }, useNull: true },
        { name: 'categoryId', convert: function(v, record) {
            return v || record.raw && record.raw.category && record.raw.category.id;
        }, useNull: true },
        { name: 'templateId', convert: function(v, record) {
            return v || record.raw && record.raw.template && record.raw.template.id;
        }, useNull: true },
        { name: 'documentTemplateId', convert: function(v, record) {
            return v || record.raw && record.raw.documentTemplate && record.raw.documentTemplate.id;
        }, useNull: true },
        { name: 'customerGroupId', convert: function(v, record) {
            return v || record.raw && record.raw.customerGroup && record.raw.customerGroup.id;
        }, useNull: true },
        { name: 'fallbackId', convert: function(v, record) {
            return v || record.raw && record.raw.fallback && record.raw.fallback.id;
        }, useNull: true },
        { name: 'deletable', type: 'boolean', convert: function(v, r) { return r.data.id > 1; } }
    ],

    associations: [{
        type: 'hasMany',
        model: 'Shopware.apps.Base.model.Currency',
        name: 'getCurrencies',
        associationKey: 'currencies'
    }, {
        type: 'hasMany',
        model: 'Shopware.apps.Config.model.form.PageGroup',
        name: 'getPages',
        associationKey: 'pages'
    }]
});
//{/block}
<commit_msg>SW-15224 - Allow reset fallback language in shop config<commit_after>/**
 * Shopware 5
 * Copyright (c) shopware AG
 *
 * According to our dual licensing model, this program can be used either
 * under the terms of the GNU Affero General Public License, version 3,
 * or under a proprietary license.
 *
 * The texts of the GNU Affero General Public License with an additional
 * permission and of our proprietary license can be found at and
 * in the LICENSE file you have received along with this program.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * "Shopware" is a registered trademark of shopware AG.
 * The licensing of the program under the AGPLv3 does not imply a
 * trademark license. Therefore any rights, title and interest in
 * our trademarks remain entirely with us.
 *
 * @category   Shopware
 * @package    Shopware_Config
 * @subpackage Config
 * @version    $Id$
 * @author shopware AG
 */

/**
 * todo@all: Documentation
 */
//{block name="backend/config/model/form/shop"}
Ext.define('Shopware.apps.Config.model.form.Shop', {
    extend:'Ext.data.Model',

    fields: [
		//{block name="backend/config/model/form/shop/fields"}{/block}
        { name: 'id', type:'int', useNull: true, defaultValue: null },
        { name: 'typeSwitch',  persist: false, convert: function(v, record) {

            // The default value determines if a newly created shop is either a subshop (sub) or a language shop (lang).
            // record.phantom is set automatically on new, unsaved records by ExtJs.
            //{block name="backend/config/model/form/shop/fields/typeSwitch/defaultValue"}
            if(record.phantom){
                return 'lang';
            }
            //{/block}

            // The shop type is internally determined by the presence/absence of the mainId
            return record.raw && record.raw.main && record.raw.main.id ? 'lang' : 'sub';
        }},
        { name: 'name', type: 'string' },
        { name: 'title', type: 'string', useNull: true },
        { name: 'position', type: 'int' },
        { name: 'name', type: 'string' },
        { name: 'default', type: 'boolean', defaultValue: false },
        { name: 'active', type: 'boolean', defaultValue: true },
        { name: 'host', type: 'string', useNull: true },
        { name: 'basePath', type: 'string', useNull: true },
        { name: 'baseUrl', type: 'string', useNull: true },
        { name: 'secure', type: 'boolean' },
        { name: 'alwaysSecure', type: 'boolean' },
        { name: 'secureHost', type: 'string', useNull: true },
        { name: 'secureBasePath', type: 'string', useNull: true },
        { name: 'hosts', type: 'string', useNull: true },
        { name: 'customerScope', type: 'boolean' },

        // Use "convert" because "mappping" not working with "useNull"
        { name: 'mainId', convert: function(v, record) {
            return v || record.raw && record.raw.main && record.raw.main.id;
        }, useNull: true, defaultValue: null },
        { name: 'localeId', convert: function(v, record) {
            return v || record.raw && record.raw.locale && record.raw.locale.id;
        }, useNull: true },
        { name: 'currencyId', convert: function(v, record) {
            return v || record.raw && record.raw.currency && record.raw.currency.id;
        }, useNull: true },
        { name: 'categoryId', convert: function(v, record) {
            return v || record.raw && record.raw.category && record.raw.category.id;
        }, useNull: true },
        { name: 'templateId', convert: function(v, record) {
            return v || record.raw && record.raw.template && record.raw.template.id;
        }, useNull: true },
        { name: 'documentTemplateId', convert: function(v, record) {
            return v || record.raw && record.raw.documentTemplate && record.raw.documentTemplate.id;
        }, useNull: true },
        { name: 'customerGroupId', convert: function(v, record) {
            return v || record.raw && record.raw.customerGroup && record.raw.customerGroup.id;
        }, useNull: true },
        { name: 'fallbackId', convert: function(v, record) {
            if (v || v === null) {
                return v;
            }
            return record.raw && record.raw.fallback && record.raw.fallback.id;
        }, useNull: true },
        { name: 'deletable', type: 'boolean', convert: function(v, r) { return r.data.id > 1; } }
    ],

    associations: [{
        type: 'hasMany',
        model: 'Shopware.apps.Base.model.Currency',
        name: 'getCurrencies',
        associationKey: 'currencies'
    }, {
        type: 'hasMany',
        model: 'Shopware.apps.Config.model.form.PageGroup',
        name: 'getPages',
        associationKey: 'pages'
    }]
});
//{/block}
<|endoftext|>


<commit_before>import React from 'react'
import './styles.css'

const DetailsHeader = ({
  id,
  name,
  description,
  party,
  imagePath,
  speechSummary,
  subjectSummary,
  voteSummary,
}) => {

  let timeInStand = 0;
  if (speechSummary && speechSummary.Samtals) {
    let minutes = parseFloat(speechSummary.Samtals.minutes)
    if (minutes !== 0) {
      if (minutes <= 60) {
        timeInStand = `${Math.round(minutes)}min`;
      } else {
        timeInStand = `${parseFloat(minutes/60).toFixed(1)}klst`;
      }
    } else {
      timeInStand = `Aldrei`;
    }
  }

  return (

        <div
          className="DetailsHeader-image"
          style={{
            backgroundImage: `url(${imagePath})`
          }}
        >

{name}
{party}

{description}

{voteSummary.voteSummary.numberOfVotes}

Atkvæði

{voteSummary.votePercentages.standsTaken}%

Afstaða

{timeInStand}

í Ræðustól

  )
}

DetailsHeader.propTypes = {
  id: React.PropTypes.string,
  name: React.PropTypes.string,
  profilePicture: React.PropTypes.string,
  party: React.PropTypes.string,
}

export default DetailsHeader
<commit_msg>Added party description to DetailsHeader<commit_after>import React from 'react'
import './styles.css'

const DetailsHeader = ({
  id,
  name,
  description,
  party,
  about,
  imagePath,
  speechSummary,
  subjectSummary,
  voteSummary,
}) => {

  let timeInStand = 0;
  if (speechSummary && speechSummary.Samtals) {
    let minutes = parseFloat(speechSummary.Samtals.minutes)
    if (minutes !== 0) {
      if (minutes <= 60) {
        timeInStand = `${Math.round(minutes)}min`;
      } else {
        timeInStand = `${parseFloat(minutes/60).toFixed(1)}klst`;
      }
    } else {
      timeInStand = `Aldrei`;
    }
  }

  return (

        <div
          className="DetailsHeader-image"
          style={{
            backgroundImage: `url(${imagePath})`
          }}
        >

{name}
{party}

{description || about}

{voteSummary.voteSummary.numberOfVotes}

Atkvæði

{voteSummary.votePercentages.standsTaken}%

Afstaða

{timeInStand}

í Ræðustól

  )
}

DetailsHeader.propTypes = {
  id: React.PropTypes.string,
  name: React.PropTypes.string,
  profilePicture: React.PropTypes.string,
  party: React.PropTypes.string,
}

export default DetailsHeader
<|endoftext|>


<commit_before>define("ace/snippets/groovy",["require","exports","module"], function(require, exports, module) {
"use strict";

exports.snippetText =undefined;
exports.scope = "groovy";

});
<commit_msg>Update tmp/bower_components/ace-builds/src/snippets/groovy.js<commit_after><|endoftext|>


<commit_before>/*
 ************************************
 *
 * Modular Directives
 *
 * Copyright (c) 2014 InSample, Inc.
 *
 * Released under the MIT License
 *
 ************************************
 *
 * A modular directive is a constructor for an AngularJS Directive Definition Object (DDO), cf.
 * http://docs.angularjs.org/api/ng/service/$compile
 *
 * A module directive can be extended using its `extendWith` method, described below, which returns
 * another constructor for a DDO.
 */
angular.module("insample.modular_directives", []).factory("ModularDirectiveCtor", function() {

  var modularDirectiveCtor = function() {}

  modularDirectiveCtor.prototype = {
    // Modular directives ONLY support isolate scope.
    scope: {},
    controller: function($scope) {},
    // Modular directives do NOT support link functions attached to a `link` key; instead, use
    // compile functions to return link functions. Pre-link functions are currently also NOT
    // supported.
    compile: function(tElement, tAttrs) {
      return angular.noop
    }
  }

  /*
   * Returns a constructor for an modular directive that's extended with the keys in
   * partialDdo as follows:
   *
   * If partialDdo has a function valued key (e.g. controller), the new modular directive
   * will have that value defined to be a function that first calls the caller modular directive's
   * function (if defined) and then the function in partialDdo.
   *
   * If partialDdo has an object valued key (e.g. scope), the new modular directive will have
   * that value defined to be the extension of the caller modular directive's object (if defined)
   * with the one in partialDdo.
   *
   * Otherwise the value in the new modular directive will be overwritten to be the value in
   * partialDdo for the given key.
   */
  modularDirectiveCtor.extendWith = function(partialDdo) {
    var modularDirectivePrototype = new this();
    var extendedCtor = function() {

      if (_.has(partialDdo, "link")) {
        throw new Error("Standalone link functions are not supported; please use a compile " +
          "function that returns a link function instead.")
      }

      _.each(partialDdo, function(value, key) {
        var baseValue = modularDirectivePrototype[key]
        if (_.isFunction(value)) {
          /*
           * When creating compound controllers, we need to annotate the new function with
           * dependencies for angular injection to work, and also be careful about which arguments
           * we pass to which constituent function.
           */
          if (key == "controller") {

            var inj = angular.injector()
            var baseValueAnnotations = _.isUndefined(baseValue) ? [] : inj.annotate(baseValue)
            var valueAnnotations = inj.annotate(value)
            var compoundAnnotations = _.union(baseValueAnnotations, valueAnnotations)

            var compoundFct = function() {
              if (!_.isUndefined(baseValue)) {
                baseValue.apply(null,
                  extractServices(baseValueAnnotations, compoundAnnotations, arguments))
              }
              value.apply(null,
                extractServices(valueAnnotations, compoundAnnotations, arguments));
            }

            compoundFct.$inject = compoundAnnotations
            this[key] = compoundFct

          } else if (key == "compile") {

            this[key] = function() {
              var baseLink = undefined
              if (!_.isUndefined(baseValue)) {
                baseLink = baseValue.apply(null, arguments)
              }
              var link = value.apply(null, arguments)
              return function() {
                if (!_.isUndefined(baseLink)) {
                  baseLink.apply(null, arguments)
                }
                link.apply(null, arguments)
              }
            }

          } else {

            this[key] = function() {
              if (!_.isUndefined(baseValue)) {
                baseValue.apply(null, arguments)
              }
              value.apply(null, arguments);
            }

          }

        } else if (_.isObject(value) && !_.isArray(value)) {
          this[key] = _.clone(baseValue || {})
          _.extend(this[key], value)
        } else {
          this[key] = value;
        }
      }, this)
    }

    extendedCtor.prototype = modularDirectivePrototype

    extendedCtor.extendWith = this.extendWith

    extendedCtor.wasExtendedWith = partialDdo

    return extendedCtor
  }

  /*
   * This function gets the index in `serviceNameList` of every service name in `serviceNameSublist`
   * and returns the sublist of `serviceList` that corresponds to these indices.
   *
   * Every name in `serviceNameSublist` should appear in `serviceNameList`; `serviceNameList` should
   * be exactly equal to the list of names of services in `serviceList`.
   */
  var extractServices = function(serviceNameSublist, serviceNameList, serviceList) {

    if (serviceNameList.length != serviceList.length) {
      throw new Error("The number of provided services does not equal the number of service names.")
    }

    return _.map(serviceNameSublist, function(serviceName) {
      var indexInServiceList = _.indexOf(serviceNameList, serviceName)
      if (indexInServiceList < 0) {
        throw new Error(serviceName + " was not found in the list of service names.")
      }
      return serviceList[indexInServiceList]
    })
  }

  return modularDirectiveCtor
})
<commit_msg>create serial function<commit_after>/*
 ************************************
 *
 * Modular Directives
 *
 * Copyright (c) 2014 InSample, Inc.
 *
 * Released under the MIT License
 *
 ************************************
 *
 * A modular directive is a constructor for an AngularJS Directive Definition Object (DDO), cf.
 * http://docs.angularjs.org/api/ng/service/$compile
 *
 * A modular directive can be extended using its `extendWith` method, described below, which returns
 * another modular directive.
 */
angular.module("insample.modular_directives", []).factory("ModularDirectiveCtor", function() {

  var modularDirectiveCtor = function() {}

  // Use this prototype to set DDO defaults.
  modularDirectiveCtor.prototype = {
    // Modular directives ONLY support isolate scope.
    scope: {},
    controller: function($scope) {},
    // Modular directives do NOT support link functions attached to a `link` key; instead, use
    // compile functions to return link functions. Pre-link functions are currently also NOT
    // supported.
    compile: function(tElement, tAttrs) {
      return angular.noop
    }
  }

  /*
   * Returns a constructor for an modular directive that's extended with the keys in
   * partialDdo as follows:
   *
   * If partialDdo has a function valued key (e.g. controller), the new modular directive
   * will have that value defined to be a function that first calls the caller modular directive's
   * function (if defined) and then the function in partialDdo.
   *
   * If partialDdo has an object valued key (e.g. scope), the new modular directive will have
   * that value defined to be the extension of the caller modular directive's object (if defined)
   * with the one in partialDdo.
   *
   * Otherwise the value in the new modular directive will be overwritten to be the value in
   * partialDdo for the given key.
   */
  // modularDirectiveCtor.extendWith = function(partialDdo) {
  //   var modularDirectivePrototype = new this();
  //   var extendedCtor = function() {

  //     if (_.has(partialDdo, "link")) {
  //       throw new Error("Standalone link functions are not supported; please use a compile " +
  //         "function that returns a link function instead.")
  //     }

  //     _.each(partialDdo, function(value, key) {
  //       var baseValue = modularDirectivePrototype[key]
  //       if (_.isFunction(value)) {
  //         /*
  //          * When creating compound controllers, we need to annotate the new function with
  //          * dependencies for angular injection to work, and also be careful about which arguments
  //          * we pass to which constituent function.
  //          */
  //         if (key == "controller") {

  //           var inj = angular.injector()
  //           var baseValueAnnotations = _.isUndefined(baseValue) ? [] : inj.annotate(baseValue)
  //           var valueAnnotations = inj.annotate(value)
  //           var compoundAnnotations = _.union(baseValueAnnotations, valueAnnotations)

  //           var compoundFct = function() {
  //             if (!_.isUndefined(baseValue)) {
  //               baseValue.apply(null,
  //                 extractServices(baseValueAnnotations, compoundAnnotations, arguments))
  //             }
  //             value.apply(null,
  //               extractServices(valueAnnotations, compoundAnnotations, arguments));
  //           }

  //           compoundFct.$inject = compoundAnnotations
  //           this[key] = compoundFct

  //         } else if (key == "compile") {

  //           this[key] = function() {
  //             var baseLink = undefined
  //             if (!_.isUndefined(baseValue)) {
  //               baseLink = baseValue.apply(null, arguments)
  //             }
  //             var link = value.apply(null, arguments)
  //             return function() {
  //               if (!_.isUndefined(baseLink)) {
  //                 baseLink.apply(null, arguments)
  //               }
  //               link.apply(null, arguments)
  //             }
  //           }

  //         } else {

  //           this[key] = function() {
  //             if (!_.isUndefined(baseValue)) {
  //               baseValue.apply(null, arguments)
  //             }
  //             value.apply(null, arguments);
  //           }

  //         }

  //       } else if (_.isObject(value) && !_.isArray(value)) {
  //         this[key] = _.clone(baseValue || {})
  //         _.extend(this[key], value)
  //       } else {
  //         this[key] = value;
  //       }
  //     }, this)
  //   }

  //   extendedCtor.prototype = modularDirectivePrototype

  //   extendedCtor.extendWith = this.extendWith

  //   extendedCtor.wasExtendedWith = partialDdo

  //   return extendedCtor
  // }

  /*
   * Returns a function that calls `baseFct` and then `extensionFct` in sequence. If
   * `argumentTransformFct` is provided, it is used to transform the arguments array before passing
   * it to these functions.
   */
  var createSerialFunction = function(baseFct, extensionFct, argumentsTransformFct) {

    argumentsTransformFct = argumentsTransformFct || _.identity

    return function() {
      var transformedArgs = argumentsTransformFct(arguments)
      if (!_.isUndefined(baseValue)) {
        baseValue.apply(null, transformedArgs)
      }
      value.apply(null, transformedArgs)
    }

  }

  /*
   * This function gets the index in `serviceNameList` of every service name in `serviceNameSublist`
   * and returns the sublist of `serviceList` that corresponds to these indices.
   *
   * Every name in `serviceNameSublist` should appear in `serviceNameList`; `serviceNameList` should
   * be exactly equal to the list of names of services in `serviceList`.
   */
  var extractServices = function(serviceNameSublist, serviceNameList, serviceList) {

    if (serviceNameList.length != serviceList.length) {
      throw new Error("The number of provided services does not equal the number of service names.")
    }

    return _.map(serviceNameSublist, function(serviceName) {
      var indexInServiceList = _.indexOf(serviceNameList, serviceName)
      if (indexInServiceList < 0) {
        throw new Error(serviceName + " was not found in the list of service names.")
      }
      return serviceList[indexInServiceList]
    })
  }

  return modularDirectiveCtor
})
<|endoftext|>


<commit_before>//接收者
Minder.Receiver = kity.createClass( 'Receiver', {
    clear: function () {
        this.container.innerHTML = '';
        this.selection && this.selection.setHide();
        this.range && this.range.nativeSel.removeAllRanges();
        this.index = 0;
        this.inputLength = 0;
        return this;
    },
    setTextEditStatus: function ( status ) {
        this.textEditStatus = status || false;
        return this;
    },
    isTextEditStatus: function () {
        return this.textEditStatus;
    },
    constructor: function ( km ) {
        this.setKityMinder( km );
        this.textEditStatus = false;
        var _div = document.createElement( 'div' );
        _div.setAttribute( 'contenteditable', true );
        _div.className = 'km_receiver';
        this.container = document.body.insertBefore( _div, document.body.firstChild );
        utils.addCssRule( 'km_receiver_css', ' .km_receiver{position:absolute;padding:0;margin:0;word-wrap:break-word;clip:rect(1em 1em 1em 1em);}' ); //
        this.km.on( 'textedit.beforekeyup textedit.keydown textedit.keypress textedit.paste', utils.proxy( this.keyboardEvents, this ) );
        this.timer = null;
        this.index = 0;
    },
    setRange: function ( range, index ) {

        this.index = index || this.index;

        var text = this.container.firstChild;
        this.range = range;
        range.setStart( text || this.container, this.index ).collapse( true );
        var me = this;
        setTimeout( function () {
            me.container.focus();
            range.select()
        } );
        return this;
    },
    setTextShape: function ( textShape ) {
        if ( !textShape ) {
            textShape = new kity.Text();
        }
        this.textShape = textShape;
        this.container.innerHTML = utils.unhtml(textShape.getContent());
        return this;
    },
    setTextShapeSize: function ( size ) {
        this.textShape.setSize( size );
        return this;
    },
    getTextShapeHeight: function () {
        return this.textShape.getRenderBox().height;
    },
    appendTextShapeToPaper: function ( paper ) {
        paper.addShape( this.textShape );
        return this;
    },
    setKityMinder: function ( km ) {
        this.km = km;
        return this;
    },
    setMinderNode: function ( node ) {
        this.minderNode = node;
        return this;
    },
    keyboardEvents: function ( e ) {

        clearTimeout( this.timer );
        var me = this;
        var orgEvt = e.originEvent;
        var keyCode = orgEvt.keyCode;
        var keys = KityMinder.keymap;

        function setTextToContainer() {
            var text = me.container.textContent.replace( /[\u200b\t\r\n]/g, '' );

            if ( me.textShape.getOpacity() == 0 ) {
                me.textShape.setOpacity( 1 );
            }
            //#46 修复在ff下定位到文字后方空格光标不移动问题
            if ( browser.gecko && /\s$/.test( text ) ) {
                text += "\u200b";
            }
            me.textShape.setContent( text );
            me.setContainerStyle();
            me.minderNode.setText( text );
            if ( text.length == 0 ) {
                me.minderNode.setText( 'a' );
            }
            me.km.updateLayout( me.minderNode );

            me.textShape = me.minderNode.getTextShape();
            if ( text.length == 0 ) {
                me.textShape.setOpacity( 0 );
            }
            me.setBaseOffset();
            me.updateTextData();

            me.updateIndex();
            me.updateSelection();

            me.timer = setTimeout( function () {
                me.selection.setShow()
            }, 500 );
        }
        var isTypeText = false;
        var isKeypress = false;
        switch ( e.type ) {

        case 'keydown':
            isTypeText = false;
            isKeypress = false;
            switch ( e.originEvent.keyCode ) {
            case keys.Enter:
            case keys.Tab:
                this.selection.setHide();
                this.clear().setTextEditStatus( false );
                this.km.fire( 'contentchange' );
                this.km.setStatus( 'normal' );
                e.preventDefault();
                return;
                break;
            case keymap.Shift:
            case keymap.Control:
            case keymap.Alt:
            case keymap.Cmd:
                return;
            }

            if ( e.originEvent.ctrlKey || e.originEvent.metaKey ) {

                //粘贴
                if ( keyCode == keymap.v ) {

                    setTimeout( function () {
                        me.range.updateNativeRange().insertNode( $( '$$_kityminder_bookmark_$$' )[ 0 ] );
                        me.container.innerHTML = utils.unhtml(me.container.textContent.replace( /[\u200b\t\r\n]/g, '' ));
                        var index = me.container.textContent.indexOf( '$$_kityminder_bookmark_$$' );
                        me.container.textContent = me.container.textContent.replace( '$$_kityminder_bookmark_$$', '' );
                        me.range.setStart( me.container.firstChild, index ).collapse( true ).select();
                        setTextToContainer()
                    }, 100 );
                }
                //剪切
                if ( keyCode == keymap.x ) {
                    setTimeout( function () {
                        setTextToContainer()
                    }, 100 );
                }
                return;
            }
            isTypeText = true;

            break;

        case 'keypress':
            if ( isTypeText )
                setTextToContainer();
            isKeypress = true;
            break;

        case 'beforekeyup':

            switch ( keyCode ) {
            case keymap.Enter:
            case keymap.Tab:
            case keymap.F2:
                if ( this.keydownNode === this.minderNode ) {
                    this.rollbackStatus();
                    this.setTextEditStatus( false );
                    this.clear();
                }
                e.preventDefault();
                return;

            }

            if ( !isKeypress ) {
                setTextToContainer();
            }
            return true;
        }

    },

    updateIndex: function () {
        this.index = this.range.getStart().startOffset;
        return this;
    },
    updateTextData: function () {
        this.textShape.textData = this.getTextOffsetData();
        return this;
    },
    setSelection: function ( selection ) {
        this.selection = selection;
        return this;
    },
    updateSelection: function () {
        this.selection.setShowHold();
        this.selection.bringTop();
        //更新模拟选区的范围
        this.selection.setStartOffset( this.index ).collapse( true );
        if ( this.index == this.textData.length ) {
            if ( this.index == 0 ) {
                this.selection.setPosition( this.getBaseOffset() )
            } else {
                this.selection.setPosition( {
                    x: this.textData[ this.index - 1 ].x + this.textData[ this.index - 1 ].width,
                    y: this.textData[ this.index - 1 ].y
                } )
            }

        } else {
            this.selection.setPosition( this.textData[ this.index ] )
        }
        return this;
    },
    getBaseOffset: function ( refer ) {
        var rb = this.textShape.getRenderBox( refer || this.km.getRenderContainer() );
//        if(!this.pr) {
//            this.km.getRenderContainer().addShape(this.pr = new kity.Rect().stroke('green'));
//        }
//        this.pr.setSize(rb.width, rb.height).setPosition(rb.x, rb.y);
        return rb;
    },
    setBaseOffset: function () {
        this.offset = this.textShape.getRenderBox( this.km.getRenderContainer() );
        return this;
    },
    setContainerStyle: function () {
        var textShapeBox = this.getBaseOffset('screen');
        this.container.style.cssText = ";left:" + textShapeBox.x + 'px;top:' + ( textShapeBox.y - 5 ) + 'px;width:' + textShapeBox.width + 'px;height:' + textShapeBox.height + 'px;';

        if(!this.selection.isShow()){
            var paperContainer = this.km.getPaper();
            var width = paperContainer.getWidth();
            var height = paperContainer.getHeight();

            if(width < this.container.offsetWidth + this.container.offsetLeft){
                this.km.getRenderContainer().translate(width/-3, 0);
                this.setContainerStyle();

            }else if (height < this.container.offsetTop + this.container.offsetHeight){
                this.km.getRenderContainer().translate(0, height/-3);
                this.setContainerStyle()
            }
        }

        return this;
    },
    getTextOffsetData: function () {
        var text = this.textShape.getContent();
        this.textData = [];

        for ( var i = 0, l = text.length; i < l; i++ ) {
            try {
                var box = this.textShape.getExtentOfChar( i );
            } catch ( e ) {
                console.log(e)
            }

            this.textData.push( {
                x: box.x + this.offset.x,
                y: this.offset.y,
                width: box.width,
                height: box.height
            } )
        }
        return this;
    },
    setCurrentIndex: function ( offset ) {
        var me = this;
        this.getTextOffsetData();
        var hadChanged = false;
        utils.each( this.textData, function ( i, v ) {
            //点击开始之前
            if ( i == 0 && offset.x <= v.x ) {
                me.index = 0;
                return false;
            }
            if ( offset.x >= v.x && offset.x <= v.x + v.width ) {
                if ( offset.x - v.x > v.width / 2 ) {
                    me.index = i + 1;

                } else {
                    me.index = i

                }
                hadChanged = true;
                return false;
            }
            if ( i == me.textData.length - 1 && offset.x >= v.x ) {
                me.index = me.textData.length;
                return false;
            }
        } );

        return this;

    },
    setSelectionHeight: function () {
        this.selection.setHeight( this.getTextShapeHeight() );
        return this;
    },

    updateSelectionByMousePosition: function ( offset, dir ) {

        var me = this;
        utils.each( this.textData, function ( i, v ) {
            //点击开始之前
            if ( i == 0 && offset.x <= v.x ) {
                me.selection.setStartOffset( 0 );
                return false;
            }

            if ( i == me.textData.length - 1 && offset.x >= v.x ) {
                me.selection.setEndOffset( me.textData.length );
                return false;
            }
            if ( offset.x >= v.x && offset.x <= v.x + v.width ) {

                if ( me.index == i ) {
                    if ( i == 0 ) {
                        me.selection.setStartOffset( i )
                    }
                    if ( offset.x <= v.x + v.width / 2 ) {
                        me.selection.collapse()
                    } else {
                        me.selection.setEndOffset( i + ( me.selection.endOffset > i || dir == 1 ? 1 : 0 ) )
                    }

                } else if ( i > me.index ) {
                    me.selection.setStartOffset( me.index );
                    me.selection.setEndOffset( i + 1 )
                } else {
                    if ( dir == 1 ) {
                        me.selection.setStartOffset( i + ( offset.x >= v.x + v.width / 2 ? 1 : 0 ) );
                    } else {
                        me.selection.setStartOffset( i );
                    }

                    me.selection.setEndOffset( me.index )
                }

                return false;
            }
        } );
        return this;
    },
    updateSelectionShow: function () {
        var startOffset = this.textData[ this.selection.startOffset ],
            endOffset = this.textData[ this.selection.endOffset ],
            width = 0;
        if ( this.selection.collapsed ) {
            this.selection.updateShow( startOffset || this.textData[ this.textData.length - 1 ],1 );
            return this;
        }
        if ( !endOffset ) {
            var lastOffset = this.textData[ this.textData.length - 1 ];
            width = lastOffset.x - startOffset.x + lastOffset.width;
        } else {
            width = endOffset.x - startOffset.x;
        }

        this.selection.updateShow( startOffset, width );
        return this;
    },
    updateRange: function ( range ) {
        var node = this.container.firstChild;
        range.setStart( node, this.selection.startOffset );
        range.setEnd( node, this.selection.endOffset );
        range.select();
        return this;
    },
    setIndex: function ( index ) {
        this.index = index;
        return this
    },
    setContainerTxt: function ( txt ) {
        this.container.textContent = txt;
        return this;
    }
} );<commit_msg>fix width check on firefox<commit_after>//接收者
Minder.Receiver = kity.createClass( 'Receiver', {
    clear: function () {
        this.container.innerHTML = '';
        this.selection && this.selection.setHide();
        this.range && this.range.nativeSel.removeAllRanges();
        this.index = 0;
        this.inputLength = 0;
        return this;
    },
    setTextEditStatus: function ( status ) {
        this.textEditStatus = status || false;
        return this;
    },
    isTextEditStatus: function () {
        return this.textEditStatus;
    },
    constructor: function ( km ) {
        this.setKityMinder( km );
        this.textEditStatus = false;
        var _div = document.createElement( 'div' );
        _div.setAttribute( 'contenteditable', true );
        _div.className = 'km_receiver';
        this.container = document.body.insertBefore( _div, document.body.firstChild );
        utils.addCssRule( 'km_receiver_css', ' .km_receiver{position:absolute;padding:0;margin:0;word-wrap:break-word;clip:rect(1em 1em 1em 1em);}' ); //
        this.km.on( 'textedit.beforekeyup textedit.keydown textedit.keypress textedit.paste', utils.proxy( this.keyboardEvents, this ) );
        this.timer = null;
        this.index = 0;
    },
    setRange: function ( range, index ) {

        this.index = index || this.index;

        var text = this.container.firstChild;
        this.range = range;
        range.setStart( text || this.container, this.index ).collapse( true );
        var me = this;
        setTimeout( function () {
            me.container.focus();
            range.select()
        } );
        return this;
    },
    setTextShape: function ( textShape ) {
        if ( !textShape ) {
            textShape = new kity.Text();
        }
        this.textShape = textShape;
        this.container.innerHTML = utils.unhtml(textShape.getContent());
        return this;
    },
    setTextShapeSize: function ( size ) {
        this.textShape.setSize( size );
        return this;
    },
    getTextShapeHeight: function () {
        return this.textShape.getRenderBox().height;
    },
    appendTextShapeToPaper: function ( paper ) {
        paper.addShape( this.textShape );
        return this;
    },
    setKityMinder: function ( km ) {
        this.km = km;
        return this;
    },
    setMinderNode: function ( node ) {
        this.minderNode = node;
        return this;
    },
    keyboardEvents: function ( e ) {

        clearTimeout( this.timer );
        var me = this;
        var orgEvt = e.originEvent;
        var keyCode = orgEvt.keyCode;
        var keys = KityMinder.keymap;

        function setTextToContainer() {
            var text = me.container.textContent.replace( /[\u200b\t\r\n]/g, '' );

            if ( me.textShape.getOpacity() == 0 ) {
                me.textShape.setOpacity( 1 );
            }
            //#46 修复在ff下定位到文字后方空格光标不移动问题
            if ( browser.gecko && /\s$/.test( text ) ) {
                text += "\u200b";
            }
            me.textShape.setContent( text );
            me.setContainerStyle();
            me.minderNode.setText( text );
            if ( text.length == 0 ) {
                me.minderNode.setText( 'a' );
            }
            me.km.updateLayout( me.minderNode );

            me.textShape = me.minderNode.getTextShape();
            if ( text.length == 0 ) {
                me.textShape.setOpacity( 0 );
            }
            me.setBaseOffset();
            me.updateTextData();

            me.updateIndex();
            me.updateSelection();

            me.timer = setTimeout( function () {
                me.selection.setShow()
            }, 500 );
        }
        var isTypeText = false;
        var isKeypress = false;
        switch ( e.type ) {

        case 'keydown':
            isTypeText = false;
            isKeypress = false;
            switch ( e.originEvent.keyCode ) {
            case keys.Enter:
            case keys.Tab:
                this.selection.setHide();
                this.clear().setTextEditStatus( false );
                this.km.fire( 'contentchange' );
                this.km.setStatus( 'normal' );
                e.preventDefault();
                return;
                break;
            case keymap.Shift:
            case keymap.Control:
            case keymap.Alt:
            case keymap.Cmd:
                return;
            }

            if ( e.originEvent.ctrlKey || e.originEvent.metaKey ) {

                //粘贴
                if ( keyCode == keymap.v ) {

                    setTimeout( function () {
                        me.range.updateNativeRange().insertNode( $( '$$_kityminder_bookmark_$$' )[ 0 ] );
                        me.container.innerHTML = utils.unhtml(me.container.textContent.replace( /[\u200b\t\r\n]/g, '' ));
                        var index = me.container.textContent.indexOf( '$$_kityminder_bookmark_$$' );
                        me.container.textContent = me.container.textContent.replace( '$$_kityminder_bookmark_$$', '' );
                        me.range.setStart( me.container.firstChild, index ).collapse( true ).select();
                        setTextToContainer()
                    }, 100 );
                }
                //剪切
                if ( keyCode == keymap.x ) {
                    setTimeout( function () {
                        setTextToContainer()
                    }, 100 );
                }
                return;
            }
            isTypeText = true;

            break;

        case 'keypress':
            if ( isTypeText )
                setTextToContainer();
            isKeypress = true;
            break;

        case 'beforekeyup':

            switch ( keyCode ) {
            case keymap.Enter:
            case keymap.Tab:
            case keymap.F2:
                if ( this.keydownNode === this.minderNode ) {
                    this.rollbackStatus();
                    this.setTextEditStatus( false );
                    this.clear();
                }
                e.preventDefault();
                return;

            }

            if ( !isKeypress ) {
                setTextToContainer();
            }
            return true;
        }

    },

    updateIndex: function () {
        this.index = this.range.getStart().startOffset;
        return this;
    },
    updateTextData: function () {
        this.textShape.textData = this.getTextOffsetData();
        return this;
    },
    setSelection: function ( selection ) {
        this.selection = selection;
        return this;
    },
    updateSelection: function () {
        this.selection.setShowHold();
        this.selection.bringTop();
        //更新模拟选区的范围
        this.selection.setStartOffset( this.index ).collapse( true );
        if ( this.index == this.textData.length ) {
            if ( this.index == 0 ) {
                this.selection.setPosition( this.getBaseOffset() )
            } else {
                this.selection.setPosition( {
                    x: this.textData[ this.index - 1 ].x + this.textData[ this.index - 1 ].width,
                    y: this.textData[ this.index - 1 ].y
                } )
            }

        } else {
            this.selection.setPosition( this.textData[ this.index ] )
        }
        return this;
    },
    getBaseOffset: function ( refer ) {
        var rb = this.textShape.getRenderBox( refer || this.km.getRenderContainer() );
//        if(!this.pr) {
//            this.km.getRenderContainer().addShape(this.pr = new kity.Rect().stroke('green'));
//        }
//        this.pr.setSize(rb.width, rb.height).setPosition(rb.x, rb.y);
        return rb;
    },
    setBaseOffset: function () {
        this.offset = this.textShape.getRenderBox( this.km.getRenderContainer() );
        return this;
    },
    setContainerStyle: function () {
        var textShapeBox = this.getBaseOffset('screen');
        this.container.style.cssText = ";left:" + textShapeBox.x + 'px;top:' + ( textShapeBox.y - 5 ) + 'px;width:' + textShapeBox.width + 'px;height:' + textShapeBox.height + 'px;';

        if(!this.selection.isShow()){
            var paperContainer = this.km.getPaper();
            var width = paperContainer.node.parentNode.clientWidth;
            var height = paperContainer.node.parentNode.clientHeight;

            if(width < this.container.offsetWidth + this.container.offsetLeft){
                this.km.getRenderContainer().translate(width/-3, 0);
                //this.setContainerStyle();
                console.log(width, this.container.offsetWidth + this.container.offsetLeft);

            }else if (height < this.container.offsetTop + this.container.offsetHeight){
                this.km.getRenderContainer().translate(0, height/-3);
                //this.setContainerStyle()
            }
        }

        return this;
    },
    getTextOffsetData: function () {
        var text = this.textShape.getContent();
        this.textData = [];

        for ( var i = 0, l = text.length; i < l; i++ ) {
            try {
                var box = this.textShape.getExtentOfChar( i );
            } catch ( e ) {
                console.log(e)
            }

            this.textData.push( {
                x: box.x + this.offset.x,
                y: this.offset.y,
                width: box.width,
                height: box.height
            } )
        }
        return this;
    },
    setCurrentIndex: function ( offset ) {
        var me = this;
        this.getTextOffsetData();
        var hadChanged = false;
        utils.each( this.textData, function ( i, v ) {
            //点击开始之前
            if ( i == 0 && offset.x <= v.x ) {
                me.index = 0;
                return false;
            }
            if ( offset.x >= v.x && offset.x <= v.x + v.width ) {
                if ( offset.x - v.x > v.width / 2 ) {
                    me.index = i + 1;

                } else {
                    me.index = i

                }
                hadChanged = true;
                return false;
            }
            if ( i == me.textData.length - 1 && offset.x >= v.x ) {
                me.index = me.textData.length;
                return false;
            }
        } );

        return this;

    },
    setSelectionHeight: function () {
        this.selection.setHeight( this.getTextShapeHeight() );
        return this;
    },

    updateSelectionByMousePosition: function ( offset, dir ) {

        var me = this;
        utils.each( this.textData, function ( i, v ) {
            //点击开始之前
            if ( i == 0 && offset.x <= v.x ) {
                me.selection.setStartOffset( 0 );
                return false;
            }

            if ( i == me.textData.length - 1 && offset.x >= v.x ) {
                me.selection.setEndOffset( me.textData.length );
                return false;
            }
            if ( offset.x >= v.x && offset.x <= v.x + v.width ) {

                if ( me.index == i ) {
                    if ( i == 0 ) {
                        me.selection.setStartOffset( i )
                    }
                    if ( offset.x <= v.x + v.width / 2 ) {
                        me.selection.collapse()
                    } else {
                        me.selection.setEndOffset( i + ( me.selection.endOffset > i || dir == 1 ? 1 : 0 ) )
                    }

                } else if ( i > me.index ) {
                    me.selection.setStartOffset( me.index );
                    me.selection.setEndOffset( i + 1 )
                } else {
                    if ( dir == 1 ) {
                        me.selection.setStartOffset( i + ( offset.x >= v.x + v.width / 2 ? 1 : 0 ) );
                    } else {
                        me.selection.setStartOffset( i );
                    }

                    me.selection.setEndOffset( me.index )
                }

                return false;
            }
        } );
        return this;
    },
    updateSelectionShow: function () {
        var startOffset = this.textData[ this.selection.startOffset ],
            endOffset = this.textData[ this.selection.endOffset ],
            width = 0;
        if ( this.selection.collapsed ) {
            this.selection.updateShow( startOffset || this.textData[ this.textData.length - 1 ],1 );
            return this;
        }
        if ( !endOffset ) {
            var lastOffset = this.textData[ this.textData.length - 1 ];
            width = lastOffset.x - startOffset.x + lastOffset.width;
        } else {
            width = endOffset.x - startOffset.x;
        }

        this.selection.updateShow( startOffset, width );
        return this;
    },
    updateRange: function ( range ) {
        var node = this.container.firstChild;
        range.setStart( node, this.selection.startOffset );
        range.setEnd( node, this.selection.endOffset );
        range.select();
        return this;
    },
    setIndex: function ( index ) {
        this.index = index;
        return this
    },
    setContainerTxt: function ( txt ) {
        this.container.textContent = txt;
        return this;
    }
} );<|endoftext|>