(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else {
		var a = factory();
		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
	}
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 300);
/******/ })
/************************************************************************/
/******/ ({

/***/ 0:
/***/ (function(module, exports) {

/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
// css base code, injected by the css-loader
module.exports = function(useSourceMap) {
	var list = [];

	// return the list of modules as css string
	list.toString = function toString() {
		return this.map(function (item) {
			var content = cssWithMappingToString(item, useSourceMap);
			if(item[2]) {
				return "@media " + item[2] + "{" + content + "}";
			} else {
				return content;
			}
		}).join("");
	};

	// import a list of modules into the list
	list.i = function(modules, mediaQuery) {
		if(typeof modules === "string")
			modules = [[null, modules, ""]];
		var alreadyImportedModules = {};
		for(var i = 0; i < this.length; i++) {
			var id = this[i][0];
			if(typeof id === "number")
				alreadyImportedModules[id] = true;
		}
		for(i = 0; i < modules.length; i++) {
			var item = modules[i];
			// skip already imported module
			// this implementation is not 100% perfect for weird media query combinations
			//  when a module is imported multiple times with different media queries.
			//  I hope this will never occur (Hey this way we have smaller bundles)
			if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
				if(mediaQuery && !item[2]) {
					item[2] = mediaQuery;
				} else if(mediaQuery) {
					item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
				}
				list.push(item);
			}
		}
	};
	return list;
};

function cssWithMappingToString(item, useSourceMap) {
	var content = item[1] || '';
	var cssMapping = item[3];
	if (!cssMapping) {
		return content;
	}

	if (useSourceMap && typeof btoa === 'function') {
		var sourceMapping = toComment(cssMapping);
		var sourceURLs = cssMapping.sources.map(function (source) {
			return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'
		});

		return [content].concat(sourceURLs).concat([sourceMapping]).join('\n');
	}

	return [content].join('\n');
}

// Adapted from convert-source-map (MIT)
function toComment(sourceMap) {
	// eslint-disable-next-line no-undef
	var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));
	var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;

	return '/*# ' + data + ' */';
}


/***/ }),

/***/ 1:
/***/ (function(module, exports, __webpack_require__) {

/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

var stylesInDom = {};

var	memoize = function (fn) {
	var memo;

	return function () {
		if (typeof memo === "undefined") memo = fn.apply(this, arguments);
		return memo;
	};
};

var isOldIE = memoize(function () {
	// Test for IE <= 9 as proposed by Browserhacks
	// @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
	// Tests for existence of standard globals is to allow style-loader
	// to operate correctly into non-standard environments
	// @see https://github.com/webpack-contrib/style-loader/issues/177
	return window && document && document.all && !window.atob;
});

var getElement = (function (fn) {
	var memo = {};

	return function(selector) {
		if (typeof memo[selector] === "undefined") {
			var styleTarget = fn.call(this, selector);
			// Special case to return head of iframe instead of iframe itself
			if (styleTarget instanceof window.HTMLIFrameElement) {
				try {
					// This will throw an exception if access to iframe is blocked
					// due to cross-origin restrictions
					styleTarget = styleTarget.contentDocument.head;
				} catch(e) {
					styleTarget = null;
				}
			}
			memo[selector] = styleTarget;
		}
		return memo[selector]
	};
})(function (target) {
	return document.querySelector(target)
});

var singleton = null;
var	singletonCounter = 0;
var	stylesInsertedAtTop = [];

var	fixUrls = __webpack_require__(2);

module.exports = function(list, options) {
	if (typeof DEBUG !== "undefined" && DEBUG) {
		if (typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
	}

	options = options || {};

	options.attrs = typeof options.attrs === "object" ? options.attrs : {};

	// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
	// tags it will allow on a page
	if (!options.singleton) options.singleton = isOldIE();

	// By default, add <style> tags to the <head> element
	if (!options.insertInto) options.insertInto = "head";

	// By default, add <style> tags to the bottom of the target
	if (!options.insertAt) options.insertAt = "bottom";

	var styles = listToStyles(list, options);

	addStylesToDom(styles, options);

	return function update (newList) {
		var mayRemove = [];

		for (var i = 0; i < styles.length; i++) {
			var item = styles[i];
			var domStyle = stylesInDom[item.id];

			domStyle.refs--;
			mayRemove.push(domStyle);
		}

		if(newList) {
			var newStyles = listToStyles(newList, options);
			addStylesToDom(newStyles, options);
		}

		for (var i = 0; i < mayRemove.length; i++) {
			var domStyle = mayRemove[i];

			if(domStyle.refs === 0) {
				for (var j = 0; j < domStyle.parts.length; j++) domStyle.parts[j]();

				delete stylesInDom[domStyle.id];
			}
		}
	};
};

function addStylesToDom (styles, options) {
	for (var i = 0; i < styles.length; i++) {
		var item = styles[i];
		var domStyle = stylesInDom[item.id];

		if(domStyle) {
			domStyle.refs++;

			for(var j = 0; j < domStyle.parts.length; j++) {
				domStyle.parts[j](item.parts[j]);
			}

			for(; j < item.parts.length; j++) {
				domStyle.parts.push(addStyle(item.parts[j], options));
			}
		} else {
			var parts = [];

			for(var j = 0; j < item.parts.length; j++) {
				parts.push(addStyle(item.parts[j], options));
			}

			stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};
		}
	}
}

function listToStyles (list, options) {
	var styles = [];
	var newStyles = {};

	for (var i = 0; i < list.length; i++) {
		var item = list[i];
		var id = options.base ? item[0] + options.base : item[0];
		var css = item[1];
		var media = item[2];
		var sourceMap = item[3];
		var part = {css: css, media: media, sourceMap: sourceMap};

		if(!newStyles[id]) styles.push(newStyles[id] = {id: id, parts: [part]});
		else newStyles[id].parts.push(part);
	}

	return styles;
}

function insertStyleElement (options, style) {
	var target = getElement(options.insertInto)

	if (!target) {
		throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");
	}

	var lastStyleElementInsertedAtTop = stylesInsertedAtTop[stylesInsertedAtTop.length - 1];

	if (options.insertAt === "top") {
		if (!lastStyleElementInsertedAtTop) {
			target.insertBefore(style, target.firstChild);
		} else if (lastStyleElementInsertedAtTop.nextSibling) {
			target.insertBefore(style, lastStyleElementInsertedAtTop.nextSibling);
		} else {
			target.appendChild(style);
		}
		stylesInsertedAtTop.push(style);
	} else if (options.insertAt === "bottom") {
		target.appendChild(style);
	} else if (typeof options.insertAt === "object" && options.insertAt.before) {
		var nextSibling = getElement(options.insertInto + " " + options.insertAt.before);
		target.insertBefore(style, nextSibling);
	} else {
		throw new Error("[Style Loader]\n\n Invalid value for parameter 'insertAt' ('options.insertAt') found.\n Must be 'top', 'bottom', or Object.\n (https://github.com/webpack-contrib/style-loader#insertat)\n");
	}
}

function removeStyleElement (style) {
	if (style.parentNode === null) return false;
	style.parentNode.removeChild(style);

	var idx = stylesInsertedAtTop.indexOf(style);
	if(idx >= 0) {
		stylesInsertedAtTop.splice(idx, 1);
	}
}

function createStyleElement (options) {
	var style = document.createElement("style");

	options.attrs.type = "text/css";

	addAttrs(style, options.attrs);
	insertStyleElement(options, style);

	return style;
}

function createLinkElement (options) {
	var link = document.createElement("link");

	options.attrs.type = "text/css";
	options.attrs.rel = "stylesheet";

	addAttrs(link, options.attrs);
	insertStyleElement(options, link);

	return link;
}

function addAttrs (el, attrs) {
	Object.keys(attrs).forEach(function (key) {
		el.setAttribute(key, attrs[key]);
	});
}

function addStyle (obj, options) {
	var style, update, remove, result;

	// If a transform function was defined, run it on the css
	if (options.transform && obj.css) {
	    result = options.transform(obj.css);

	    if (result) {
	    	// If transform returns a value, use that instead of the original css.
	    	// This allows running runtime transformations on the css.
	    	obj.css = result;
	    } else {
	    	// If the transform function returns a falsy value, don't add this css.
	    	// This allows conditional loading of css
	    	return function() {
	    		// noop
	    	};
	    }
	}

	if (options.singleton) {
		var styleIndex = singletonCounter++;

		style = singleton || (singleton = createStyleElement(options));

		update = applyToSingletonTag.bind(null, style, styleIndex, false);
		remove = applyToSingletonTag.bind(null, style, styleIndex, true);

	} else if (
		obj.sourceMap &&
		typeof URL === "function" &&
		typeof URL.createObjectURL === "function" &&
		typeof URL.revokeObjectURL === "function" &&
		typeof Blob === "function" &&
		typeof btoa === "function"
	) {
		style = createLinkElement(options);
		update = updateLink.bind(null, style, options);
		remove = function () {
			removeStyleElement(style);

			if(style.href) URL.revokeObjectURL(style.href);
		};
	} else {
		style = createStyleElement(options);
		update = applyToTag.bind(null, style);
		remove = function () {
			removeStyleElement(style);
		};
	}

	update(obj);

	return function updateStyle (newObj) {
		if (newObj) {
			if (
				newObj.css === obj.css &&
				newObj.media === obj.media &&
				newObj.sourceMap === obj.sourceMap
			) {
				return;
			}

			update(obj = newObj);
		} else {
			remove();
		}
	};
}

var replaceText = (function () {
	var textStore = [];

	return function (index, replacement) {
		textStore[index] = replacement;

		return textStore.filter(Boolean).join('\n');
	};
})();

function applyToSingletonTag (style, index, remove, obj) {
	var css = remove ? "" : obj.css;

	if (style.styleSheet) {
		style.styleSheet.cssText = replaceText(index, css);
	} else {
		var cssNode = document.createTextNode(css);
		var childNodes = style.childNodes;

		if (childNodes[index]) style.removeChild(childNodes[index]);

		if (childNodes.length) {
			style.insertBefore(cssNode, childNodes[index]);
		} else {
			style.appendChild(cssNode);
		}
	}
}

function applyToTag (style, obj) {
	var css = obj.css;
	var media = obj.media;

	if(media) {
		style.setAttribute("media", media)
	}

	if(style.styleSheet) {
		style.styleSheet.cssText = css;
	} else {
		while(style.firstChild) {
			style.removeChild(style.firstChild);
		}

		style.appendChild(document.createTextNode(css));
	}
}

function updateLink (link, options, obj) {
	var css = obj.css;
	var sourceMap = obj.sourceMap;

	/*
		If convertToAbsoluteUrls isn't defined, but sourcemaps are enabled
		and there is no publicPath defined then lets turn convertToAbsoluteUrls
		on by default.  Otherwise default to the convertToAbsoluteUrls option
		directly
	*/
	var autoFixUrls = options.convertToAbsoluteUrls === undefined && sourceMap;

	if (options.convertToAbsoluteUrls || autoFixUrls) {
		css = fixUrls(css);
	}

	if (sourceMap) {
		// http://stackoverflow.com/a/26603875
		css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */";
	}

	var blob = new Blob([css], { type: "text/css" });

	var oldSrc = link.href;

	link.href = URL.createObjectURL(blob);

	if(oldSrc) URL.revokeObjectURL(oldSrc);
}


/***/ }),

/***/ 13:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M28.1,21c0-2-0.7-3.7-2.1-5.1s-3.1-2.1-5.1-2.1s-3.7,0.7-5.1,2.1S13.8,19,13.8,21s0.7,3.7,2.1,5.1s3.1,2.1,5.1,2.1 s3.7-0.7,5.1-2.1S28.1,22.9,28.1,21z M37.9,18.5v4.9c0,0.2-0.1,0.3-0.2,0.5c-0.1,0.2-0.3,0.3-0.4,0.3l-4.1,0.6 c-0.3,0.8-0.6,1.5-0.9,2c0.5,0.7,1.3,1.8,2.4,3c0.1,0.2,0.2,0.4,0.2,0.6s-0.1,0.4-0.2,0.5c-0.4,0.5-1.1,1.3-2.2,2.4 c-1.1,1-1.8,1.6-2.1,1.6c-0.2,0-0.4-0.1-0.6-0.2l-3-2.4c-0.6,0.3-1.3,0.6-2,0.8c-0.2,2-0.4,3.4-0.6,4.1c-0.1,0.4-0.4,0.6-0.8,0.6 h-4.9c-0.2,0-0.4-0.1-0.5-0.2c-0.2-0.1-0.2-0.3-0.3-0.5l-0.6-4.1c-0.7-0.2-1.4-0.5-2-0.8L12,34.7c-0.1,0.1-0.3,0.2-0.6,0.2 c-0.2,0-0.4-0.1-0.6-0.2C9,33,7.8,31.8,7.2,31c-0.1-0.1-0.2-0.3-0.2-0.5c0-0.2,0.1-0.3,0.2-0.5c0.2-0.3,0.6-0.8,1.1-1.5 s0.9-1.2,1.2-1.6c-0.4-0.7-0.7-1.5-0.9-2.2l-4-0.6c-0.2,0-0.3-0.1-0.5-0.3C4.1,23.7,4,23.5,4,23.4v-4.9c0-0.2,0.1-0.3,0.2-0.5 s0.3-0.3,0.4-0.3L8.7,17c0.2-0.7,0.5-1.4,0.9-2c-0.6-0.8-1.4-1.9-2.4-3C7.1,11.8,7,11.6,7,11.4c0-0.1,0.1-0.3,0.2-0.5 c0.4-0.5,1.1-1.3,2.2-2.4S11.1,7,11.4,7c0.2,0,0.4,0.1,0.6,0.2l3,2.4c0.6-0.3,1.3-0.6,2-0.8c0.2-2,0.4-3.4,0.6-4.1 C17.8,4.2,18.1,4,18.5,4h4.9c0.2,0,0.4,0.1,0.5,0.2c0.2,0.1,0.2,0.3,0.3,0.5l0.6,4.1c0.7,0.2,1.4,0.5,2,0.8l3.1-2.4 C30.1,7,30.2,7,30.5,7c0.2,0,0.4,0.1,0.6,0.2c1.9,1.8,3.1,3,3.6,3.8c0.1,0.1,0.2,0.3,0.2,0.5c0,0.2-0.1,0.3-0.2,0.5 c-0.2,0.3-0.6,0.8-1.1,1.5c-0.5,0.7-0.9,1.2-1.2,1.6c0.4,0.7,0.7,1.5,0.9,2.2l4,0.6c0.2,0,0.3,0.1,0.5,0.3 C37.8,18.2,37.9,18.4,37.9,18.5z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 17:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M34.9,30.8V16.7c0-0.5-0.2-1-0.6-1.4s-0.8-0.6-1.4-0.6H18.8c-0.5,0-1-0.2-1.4-0.6c-0.4-0.4-0.6-0.8-0.6-1.4v-1.3 c0-0.5-0.2-1-0.6-1.4c-0.4-0.4-0.8-0.6-1.4-0.6H8.5c-0.5,0-1,0.2-1.4,0.6S6.6,11,6.6,11.5v19.3c0,0.5,0.2,1,0.6,1.4s0.8,0.6,1.4,0.6 H33c0.5,0,1-0.2,1.4-0.6S34.9,31.4,34.9,30.8z M37.5,16.7v14.2c0,1.2-0.4,2.3-1.3,3.2c-0.9,0.9-1.9,1.3-3.2,1.3H8.5 c-1.2,0-2.3-0.4-3.2-1.3S4,32.1,4,30.8V11.5c0-1.2,0.4-2.3,1.3-3.2S7.3,7,8.5,7H15c1.2,0,2.3,0.4,3.2,1.3c0.9,0.9,1.3,1.9,1.3,3.2 v0.6H33c1.2,0,2.3,0.4,3.2,1.3C37.1,14.4,37.5,15.4,37.5,16.7z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 2:
/***/ (function(module, exports) {


/**
 * When source maps are enabled, `style-loader` uses a link element with a data-uri to
 * embed the css on the page. This breaks all relative urls because now they are relative to a
 * bundle instead of the current page.
 *
 * One solution is to only use full urls, but that may be impossible.
 *
 * Instead, this function "fixes" the relative urls to be absolute according to the current page location.
 *
 * A rudimentary test suite is located at `test/fixUrls.js` and can be run via the `npm test` command.
 *
 */

module.exports = function (css) {
  // get current location
  var location = typeof window !== "undefined" && window.location;

  if (!location) {
    throw new Error("fixUrls requires window.location");
  }

	// blank or null?
	if (!css || typeof css !== "string") {
	  return css;
  }

  var baseUrl = location.protocol + "//" + location.host;
  var currentDir = baseUrl + location.pathname.replace(/\/[^\/]*$/, "/");

	// convert each url(...)
	/*
	This regular expression is just a way to recursively match brackets within
	a string.

	 /url\s*\(  = Match on the word "url" with any whitespace after it and then a parens
	   (  = Start a capturing group
	     (?:  = Start a non-capturing group
	         [^)(]  = Match anything that isn't a parentheses
	         |  = OR
	         \(  = Match a start parentheses
	             (?:  = Start another non-capturing groups
	                 [^)(]+  = Match anything that isn't a parentheses
	                 |  = OR
	                 \(  = Match a start parentheses
	                     [^)(]*  = Match anything that isn't a parentheses
	                 \)  = Match a end parentheses
	             )  = End Group
              *\) = Match anything and then a close parens
          )  = Close non-capturing group
          *  = Match anything
       )  = Close capturing group
	 \)  = Match a close parens

	 /gi  = Get all matches, not the first.  Be case insensitive.
	 */
	var fixedCss = css.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi, function(fullMatch, origUrl) {
		// strip quotes (if they exist)
		var unquotedOrigUrl = origUrl
			.trim()
			.replace(/^"(.*)"$/, function(o, $1){ return $1; })
			.replace(/^'(.*)'$/, function(o, $1){ return $1; });

		// already a full url? no change
		if (/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/)/i.test(unquotedOrigUrl)) {
		  return fullMatch;
		}

		// convert the url to a full url
		var newUrl;

		if (unquotedOrigUrl.indexOf("//") === 0) {
		  	//TODO: should we add protocol?
			newUrl = unquotedOrigUrl;
		} else if (unquotedOrigUrl.indexOf("/") === 0) {
			// path should be relative to the base url
			newUrl = baseUrl + unquotedOrigUrl; // already starts with '/'
		} else {
			// path should be relative to current directory
			newUrl = currentDir + unquotedOrigUrl.replace(/^\.\//, ""); // Strip leading './'
		}

		// send back the fixed url(...)
		return "url(" + JSON.stringify(newUrl) + ")";
	});

	// send back the fixed css
	return fixedCss;
};


/***/ }),

/***/ 300:
/***/ (function(module, exports, __webpack_require__) {

__webpack_require__(301);
__webpack_require__(302);
__webpack_require__(303);
__webpack_require__(304);
__webpack_require__(305);
__webpack_require__(306);
__webpack_require__(307);
__webpack_require__(308);
__webpack_require__(309);
__webpack_require__(310);
__webpack_require__(311);
__webpack_require__(312);
__webpack_require__(313);
__webpack_require__(314);
__webpack_require__(315);
__webpack_require__(316);
__webpack_require__(317);
__webpack_require__(318);
__webpack_require__(319);
__webpack_require__(320);
__webpack_require__(321);
__webpack_require__(322);
__webpack_require__(323);
__webpack_require__(324);
__webpack_require__(325);
__webpack_require__(326);
__webpack_require__(327);
__webpack_require__(328);


/***/ }),

/***/ 301:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * @todo        refactor this (split file, use new windows, ...)
 */

/*global Ext, Tine, Locale*/

Ext.ns('Tine.Admin');

Tine.Admin = function () {
    var registeredItems = [];
    var panels = [];

    /**
     * builds the admin applications tree
     */
    var getInitialTree = function (translation) {
        
        var _ = window.lodash,
            tree = [{
            text: translation.ngettext('User', 'Users', 50),
            cls: 'treemain',
            iconCls: 'tinebase-accounttype-user',
            allowDrag: false,
            allowDrop: true,
            id: 'accounts',
            icon: false,
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: 'accounts',
            viewRight: 'accounts'
        }, {
            text: translation.gettext('Groups'),
            cls: 'treemain',
            iconCls: 'tinebase-accounttype-group',
            allowDrag: false,
            allowDrop: true,
            id: 'groups',
            icon: false,
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: 'groups', 
            viewRight: 'accounts'
        }, {
            text: translation.gettext('Roles'),
            cls: "treemain",
            iconCls: 'tinebase-accounttype-role',
            allowDrag: false,
            allowDrop: true,
            id: "roles",
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "roles",
            viewRight: 'roles'
        }, {
            text: translation.gettext('Applications'),
            cls: "treemain",
            iconCls: 'admin-node-applications',
            allowDrag: false,
            allowDrop: true,
            id: "applications",
            icon: false,
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "applications",
            viewRight: 'apps'
        }, {
            text: translation.gettext('Containers'),
            cls: "treemain",
            iconCls: 'admin-node-containers',
            allowDrag: false,
            allowDrop: true,
            id: "containers",
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "containers",
            viewRight: 'containers'
        }, {
            text: translation.gettext('Shared Tags'),
            cls: "treemain",
            iconCls: 'action_tag',
            allowDrag: false,
            allowDrop: true,
            id: "sharedtags",
            //icon :false,
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "sharedtags",
            viewRight: 'shared_tags'
        }, {
            text: translation.gettext('Customfields'),
            cls: "treemain",
            iconCls: 'admin-node-customfields',
            allowDrag: false,
            allowDrop: true,
            id: "customfields",
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "customfields",
            viewRight: 'customfields'
        }, {
            text: translation.gettext('Computers'),
            cls: 'treemain',
            iconCls: 'admin-node-computers',
            allowDrag: false,
            allowDrop: true,
            id: 'computers',
            icon: false,
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: 'computers',
            hidden: ! Tine.Admin.registry.get('manageSAM'),
            viewRight: 'computers'
        }, {
            text: translation.gettext('Access Log'),
            cls: "treemain",
            iconCls: 'admin-node-accesslog',
            allowDrag: false,
            allowDrop: true,
            id: "accesslog",
            icon: false,
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "accesslog",
            viewRight: 'access_log'
        }, {
            text: translation.gettext('Server Information'),
            cls: "treemain",
            iconCls: 'admin-node-server-info',
            allowDrag: false,
            allowDrop: true,
            id: "serverinfo",
            children: [],
            leaf: null,
            expanded: true,
            dataPanelType: "serverinfo",
            viewRight: 'serverinfo'
        }];
        
        // TODO use hooking mechanism bellow - why is manage_devices a Tinebase right and not a ActiveSync right???
        if (Tine.Tinebase.appMgr.get('ActiveSync') && Tine.Tinebase.common.hasRight('manage_devices', 'ActiveSync')) {
            tree.push({
                text: translation.gettext('ActiveSync Devices'),
                pos: 850,
                cls: "treemain",
                iconCls: 'activesync-device-standard',
                allowDrag: false,
                allowDrop: true,
                id: "devices",
                children: [],
                leaf: null,
                expanded: true,
                dataPanelType: "devices"
            });
        }

        _.each(tree, function(item, idx) {
            item.pos = item.pos || (100 + 100 * idx);
        });
        _.each(registeredItems, function(item) {
            // NOTE: too early for appMgr :-(
            var app = item.appName ? Tine.Tinebase.appMgr.get(item.appName) : null,
                i18n = app ? app.i18n : translation;

            item.text = i18n._hidden(item.text);
            item.pos = item.pos || (200 + 100 * tree.length);

            tree.push(item);
        });


        return _.sortBy(tree, 'pos');
    };

    /**
     * register a new admin (tree) item
     * @param item
     */
    var registerItem = function(item) {
        item.dataPanelType = item.dataPanelType || Ext.id();

        registeredItems.push(Ext.applyIf(item, {
            cls: "treemain",
            allowDrag: false,
            allowDrop: true,
            children: [],
            leaf: null,
            expanded: true,
        }));
    };

    /**
     * creates the admin menu tree
     *
     */
    var getAdminTree = function () {
        
        var translation = new Locale.Gettext();
        translation.textdomain('Admin');
        
        var treeLoader = new Ext.tree.TreeLoader({
            dataUrl: 'index.php',
            baseParams: {
                jsonKey: Tine.Tinebase.registry.get('jsonKey'),
                method: 'Admin.getSubTree',
                location: 'mainTree'
            }
        });
        treeLoader.on("beforeload", function (loader, node) {
            loader.baseParams.node = node.id;
        }, this);
    
        var treePanel = new Ext.tree.TreePanel({
            title: translation.gettext('Admin'),
            id: 'admin-tree',
            iconCls: 'AdminIconCls',
            loader: treeLoader,
            rootVisible: false,
            border: false,
            autoScroll: true
        });
        
        // set the root node
        var treeRoot = new Ext.tree.TreeNode({
            text: 'root',
            draggable: false,
            allowDrop: false,
            id: 'root'
        });
        treePanel.setRootNode(treeRoot);
        
        var initialTree = getInitialTree(translation);
        
        for (var i = 0; i < initialTree.length; i += 1) {
            // check view right
            if (initialTree[i].viewRight && !Tine.Tinebase.common.hasRight('view_' + initialTree[i].viewRight, 'Admin')) {
                initialTree[i].hidden = true;
            }
            var node = new Ext.tree.AsyncTreeNode(initialTree[i]);
            treeRoot.appendChild(node);
        }
        
        treePanel.on('click', function (node, event) {
            
            if (node === null|| node.disabled) {
                return false;
            }

            Ext.ux.layout.CardLayout.helper.setActiveCardPanelItem(
                Tine.Tinebase.appMgr.get('Admin').getMainScreen().moduleCardPanel,
                new Ext.Panel({html:'', border: false, frame: false}),
                true
            );

            var _ = window.lodash,
                me = this,
                item = node.attributes,
                dataPanelType = item.dataPanelType;

            switch (dataPanelType) {
            case 'accesslog':
                Tine.Admin.accessLog.show();
                break;
            case 'accounts':
                Tine.Admin.user.show();
                break;
            case 'groups':
                Tine.Admin.Groups.Main.show();
                break;
            case 'computers':
                Tine.Admin.sambaMachine.show();
                break;
            case 'applications':
                Tine.Admin.Applications.Main.show();
                break;
            case 'sharedtags':
                Tine.Admin.Tags.Main.show();
                break;
            case 'roles':
                Tine.Admin.Roles.Main.show();
                break;
            case 'containers':
                Tine.Admin.container.show();
                break;
            case 'customfields':
                Tine.Admin.customfield.show();
                break;
            case 'serverinfo':
                Tine.Admin.getServerInfo(function(response) {
                   Tine.log.debug('Tine.Admin.getServerInfo()');
                   
                   if (! this.infoPanel) {
                       this.infoPanel = new Ext.Panel({
                           canonicalName: 'ServerInfo',
                           html: response.html,
                           autoScroll: true
                       });
                   } else {
                       this.infoPanel.update(response.html);
                   }
                   if (! this.infoPanelToolbar) {
                       // TODO add correct Tine 2.0 Toolbar layout with border
                       this.infoPanelToolbar = new Ext.Toolbar({items: [{
                           text: translation.gettext('Refresh'),
                           handler: function() {
                               node.fireEvent('click', node);
                           },
                           iconCls: 'action_login',
                           scale: 'medium',
                           rowspan: 2,
                           iconAlign: 'top'
                       }]});
                   }
                   Tine.Tinebase.MainScreen.setActiveContentPanel(this.infoPanel, true);
                   Tine.Tinebase.MainScreen.setActiveToolbar(this.infoPanelToolbar, true);
                }, this);
                break;
            // TODO find a generic hooking mechanism
            case 'devices':
                Tine.ActiveSync.syncdevices.show();
                break;

            default:
                if (! panels[dataPanelType]) {
                    panels[dataPanelType] = new item.panel();
                }

                var contentPanel = panels[dataPanelType],
                    actionToolbar;

                if (! _.isFunction(contentPanel.getActionToolbar)) {
                    actionToolbar = new Ext.Toolbar();
                    contentPanel.getActionToolbar = function() {return actionToolbar};
                }

                Tine.Tinebase.appMgr.get('Admin').getMainScreen().setActiveContentPanel(contentPanel, true);
                Tine.Tinebase.appMgr.get('Admin').getMainScreen().setActiveToolbar(contentPanel.getActionToolbar(), true);
            }
        }, this);

        treePanel.on('beforeexpand', function (panel) {
            if (panel.getSelectionModel().getSelectedNode() === null) {
                panel.expandPath('/root');
                // don't open 'applications' if user has no right to manage apps
                if (Tine.Tinebase.common.hasRight('manage', 'Admin', 'accounts')) {
                    panel.selectPath('/root/accounts');
                } else {
                    treeRoot.eachChild(function (node) {
                        if (Tine.Tinebase.common.hasRight('manage', 'Admin', node.attributes.viewRight)) {
                            panel.selectPath('/root/' + node.id);
                            return;
                        }
                    }, this);
                }
            }
            panel.fireEvent('click', panel.getSelectionModel().getSelectedNode());
        }, this);

        treePanel.on('contextmenu', function (node, event) {
            event.stopEvent();
        });

        return treePanel;
    };
    
    // public functions and variables
    return {
        registerItem: registerItem,
        getPanel: getAdminTree
    };
    
}();


/***/ }),

/***/ 302:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @package     Admin
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schuele <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2010 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.namespace('Tine.Admin');

/**
 * admin settings panel
 * 
 * @namespace   Tine.Admin
 * @class       Tine.Admin.AdminPanel
 * @extends     Tine.widgets.dialog.AdminPanel
 * 
 * <p>Admin Admin Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schuele <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2010 Metaways Infosystems GmbH (http://www.metaways.de)
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Admin.AdminPanel
 */
Tine.Admin.AdminPanel = Ext.extend(Tine.widgets.dialog.AdminPanel, {
    /**
     * @private
     */
    appName: 'Admin',

    /**
     * get config items
     *
     * @return {Array}
     */
    getConfigItems: function() {
        return [[{
            xtype: 'tinerecordpickercombobox',
            fieldLabel: this.app.i18n._('Default Addressbook for new contacts and groups'),
            name: 'defaultInternalAddressbook',
            blurOnSelect: true,
            recordClass: Tine.Tinebase.Model.Container,
            recordProxy: Tine.Admin.sharedAddressbookBackend
        }]];
    }
});

/**
 * admin panel on update function
 *
 * TODO         update registry without reloading the mainscreen
 */
Tine.Admin.AdminPanel.onUpdate = function() {
    // reload mainscreen to make sure registry gets updated
    Tine.Tinebase.common.reload();
}

/**
 * Admin admin settings popup
 * 
 * @param   {Object} config
 * @return  {Ext.ux.Window}
 */
Tine.Admin.AdminPanel.openWindow = function (config) {
    var window = Tine.WindowFactory.getWindow({
        width: 600,
        height: 400,
        name: Tine.Admin.AdminPanel.prototype.windowNamePrefix + Ext.id(),
        contentPanelConstructor: 'Tine.Admin.AdminPanel',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 303:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @package     Admin
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2009-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */
 
Ext.ns('Tine.Admin.Model');

/**
 * @namespace   Tine.Admin.Model
 * @class       Tine.Admin.Model.TagRight
 * @extends     Ext.data.Record
 * 
 * TagRight Record Definition
 */ 
Tine.Admin.Model.TagRight = Ext.data.Record.create([
    {name: 'account_id'},
    {name: 'account_type'},
    {name: 'account_name'},
    {name: 'account_data'},
    {name: 'view_right', type: 'boolean'},
    {name: 'use_right',  type: 'boolean'}
]);

/**
 * @namespace   Tine.Admin.Model
 * @class       Tine.Admin.Model.AccessLog
 * @extends     Tine.Tinebase.data.Record
 * 
 * AccessLog Record Definition
 */ 
Tine.Admin.Model.AccessLog = Tine.Tinebase.data.Record.create([
    {name: 'sessionid'},
    {name: 'login_name'},
    {name: 'ip'},
    {name: 'li', type: 'date', dateFormat: Date.patterns.ISO8601Long},
    {name: 'lo', type: 'date', dateFormat: Date.patterns.ISO8601Long},
    {name: 'id'},
    {name: 'account_id'},
    {name: 'result'},
    {name: 'clienttype'}
], {
    appName: 'Admin',
    modelName: 'AccessLog',
    idProperty: 'id',
    titleProperty: 'login_name',
    // ngettext('Access Log', 'Access Logs', n);
    recordName: 'AccessLog',
    recordsName: 'AccessLogs'
});

/**
 * AccessLog data proxy
 * 
 * @type Tine.Tinebase.data.RecordProxy
 */ 
Tine.Admin.accessLogBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'AccessLog',
    recordClass: Tine.Admin.Model.AccessLog,
    idProperty: 'id'
});

/**
 * @namespace Tine.Admin.Model
 * @class     Tine.Admin.Model.Group
 * @extends   Tine.Admin.data.Record
 * 
 * Model of a user group
 */
Tine.Admin.Model.Group = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.genericFields.concat([
    {name: 'id'},
    {name: 'name'},
    {name: 'description'},
    {name: 'container_id'},
    {name: 'visibility'}
    //{name: 'groupMembers'}
]), {
    appName: 'Admin',
    modelName: 'Group',
    idProperty: 'id',
    titleProperty: 'name',
    // ngettext('Group', 'Groups', n); gettext('Groups');
    recordName: 'Group',
    recordsName: 'Groups'
});

/**
 * returns default group data
 * 
 * @namespace Tine.Admin.Model.Group
 * @static
 * @return {Object} default data
 */
Tine.Admin.Model.Group.getDefaultData = function () {
    var internalAddressbook = Tine.Admin.registry.get('defaultInternalAddressbook');
    
    return {
        visibility: (internalAddressbook !== null) ? 'displayed' : 'hidden',
        container_id: internalAddressbook
    };
};

/**
 * @namespace Tine.Admin.Model
 * @class     Tine.Admin.Model.Application
 * @extends   Tine.Admin.data.Record
 * 
 * Model of an application
 */
Tine.Admin.Model.Application = Tine.Tinebase.data.Record.create([
    {name: 'id'},
    {name: 'name'},
    {name: 'i18nName'},
    {name: 'status'},
    {name: 'order'},
    {name: 'app_tables'},
    {name: 'version'}
], {
    appName: 'Admin',
    modelName: 'Application',
    idProperty: 'id',
    titleProperty: 'name',
    // ngettext('Application', 'Applications', n); gettext('Applications');
    recordName: 'Application',
    recordsName: 'Applications'
});

/**
 * @namespace Tine.Admin.Model
 * @class     Tine.Admin.Model.Config
 * @extends   Tine.Admin.data.Record
 *
 * Model of a application config settings
 */
Tine.Admin.Model.Config = Tine.Tinebase.data.Record.create([
    {name: 'id'},
    {name: 'application_id'},
    {name: 'name'},
    {name: 'value'},
    {name: 'label'},
    {name: 'description'},
    {name: 'type'},
    {name: 'options'},
    {name: 'clientRegistryInclude'},
    {name: 'setByAdminModule'},
    {name: 'setBySetupModule'},
    {name: 'default'},
    {name: 'source'}
    //{name: 'settings'}
], {
    appName: 'Admin',
    modelName: 'Config',
    idProperty: 'id',
    titleProperty: 'name',
    // ngettext('Config', 'Configs', n); gettext('Configs');
    recordName: 'Config',
    recordsName: 'Configs'
});

/***/ }),

/***/ 304:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         refactor this
 * TODO         translate strings (enable/disable/settings)
 */
 
Ext.ns('Tine.Admin', 'Tine.Admin.Applications');

/*********************************** MAIN DIALOG ********************************************/

Tine.Admin.Applications.Main = {

    init: function() {
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');

        this._action_enable = new Ext.Action({
            text: this.translation.gettext('Enable Application'),
            disabled: true,
            handler: this._enableDisableButtonHandler.createDelegate(this, ['enabled']),
            scope: this,
            iconCls: 'action_enable'
        });

        this._action_disable = new Ext.Action({
            text: this.translation.gettext('Disable Application'),
            disabled: true,
            handler: this._enableDisableButtonHandler.createDelegate(this, ['disabled']),
            scope: this,
            iconCls: 'action_disable'
        });

        this._action_settings = new Ext.Action({
            text: this.translation.gettext('Settings'),
            disabled: true,
            handler: this._settingsHandler,
            scope: this,
            iconCls: 'action_settings'
        });
    },

    /**
     * onclick handler for edit action
     * 
     * TODO     make that more generic?
     */
    _settingsHandler: function(_button, _event) {
        var selModel = this.gridPanel.getSelectionModel();
        if (selModel.getCount() > 0) {
            var selectedRows = selModel.getSelections();
            var appName = selectedRows[0].data.name;
            if (Tine[appName]) {
                this._openSettingsWindow(appName);
            }
        } else {
            _button.setDisabled(true);
        }
    },
    
    _openSettingsWindow: function(appName) {
        Tine[appName].AdminPanel.openWindow({
            record: (Tine[appName].Model.Settings) ? new Tine[appName].Model.Settings(appName) : null,
            title: String.format(this.translation.gettext('{0} Settings'), this.translateAppTitle(appName)),
            listeners: {
                scope: this,
                'update': (Tine[appName].AdminPanel.onUpdate) ? Tine[appName].AdminPanel.onUpdate : Ext.emptyFn
            }
        });
    },

    _enableDisableButtonHandler: function(state) {
        var applicationIds = new Array();
        var selectedRows = this.gridPanel.getSelectionModel().getSelections();
        for (var i = 0; i < selectedRows.length; ++i) {
            applicationIds.push(selectedRows[i].id);
        }
        
        Ext.Ajax.request({
            url : 'index.php',
            method : 'post',
            params : {
                method : 'Admin.setApplicationState',
                applicationIds : applicationIds,
                state: state
            },
            callback : function(_options, _success, _response) {
                if(_success === true) {
                    var result = Ext.util.JSON.decode(_response.responseText);
                    if(result.success === true) {
                        // reload mainscreen because apps have to be loaded / unloaded
                        Tine.Tinebase.common.reload();
                    }
                }
            }
        });
    },
    
    _createApplicationaDataStore: function() {
        /**
         * the datastore for lists
         */
        var ds_applications = new Ext.data.JsonStore({
            url: 'index.php',
            baseParams: {
                method: 'Admin.getApplications'
            },
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Admin.Model.Application,
            // turn on remote sorting
            remoteSort: true
        });
        
        ds_applications.setDefaultSort('name', 'asc');

        ds_applications.on('beforeload', function(_dataSource, _options) {
            _options = _options || {};
            _options.params = _options.params || {};
            _options.params.filter = Ext.getCmp('ApplicationsAdminQuickSearchField').getValue();
        });
        
        //ds_applications.load({params:{start:0, limit:50}});
        
        return ds_applications;
    },

    _showApplicationsToolbar: function() {
        // if toolbar was allready created set active toolbar and return
        if (this.actionToolbar)
        {
            Tine.Tinebase.MainScreen.setActiveToolbar(this.actionToolbar, true);
            return;
        }
        
        this._action_enable.setText(this.translation.gettext('enable application'));
        this._action_disable.setText(this.translation.gettext('disable application'));
        this._action_settings.setText(this.translation.gettext('settings'));
    
        var ApplicationsAdminQuickSearchField = new Ext.ux.SearchField({
            id: 'ApplicationsAdminQuickSearchField',
            width:240,
            emptyText: i18n._hidden('enter searchfilter')
        });
        ApplicationsAdminQuickSearchField.on('change', function() {
            this.gridPanel.getStore().load({params:{start:0, limit:50}});
        }, this);
        
        this.actionToolbar = new Ext.Toolbar({
            canonicalName: ['Application', 'ActionToolbar'].join(Tine.Tinebase.CanonicalPath.separator),
            split: false,
            //height: 26,
            items: [{
                xtype: 'buttongroup',
                columns: 7,
                items: [
                    Ext.apply(new Ext.Button(this._action_enable), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                    }), {xtype: 'tbspacer', width: 10},
                    Ext.apply(new Ext.Button(this._action_disable), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }), {xtype: 'tbspacer', width: 10},
                    {xtype: 'tbseparator'}, {xtype: 'tbspacer', width: 10},
                    Ext.apply(new Ext.Button(this._action_settings), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    })
                ]
            }, '->',
                this.translation.gettext('Search:'), ' ',
//                new Ext.ux.SelectBox({
//                    listClass:'x-combo-list-small',
//                      width:90,
//                      value:'Starts with',
//                      id:'search-type',
//                      store: new Ext.data.SimpleStore({
//                        fields: ['text'],
//                        expandData: true,
//                        data : ['Starts with', 'Ends with', 'Any match']
//                      }),
//                      displayField: 'text'
//                }),
                ' ',
                ApplicationsAdminQuickSearchField
            ]
        });
        
        Tine.Tinebase.MainScreen.setActiveToolbar(this.actionToolbar, true);
    },
    
    /**
     * translate and return app title
     * 
     * TODO try to generalize this fn as this gets used in Tags.js + RoleEditDialog.js as well 
     *      -> this could be moved to Tine.Admin.Application after Admin js refactoring
     */
    translateAppTitle: function(appName) {
        var app = Tine.Tinebase.appMgr.get(appName);
        return (app) ? app.getTitle() : appName;
    },

    /**
     * render enabled field (translate)
     */
    _renderEnabled: function(_value, _cellObject, _record, _rowIndex, _colIndex, _dataStore) {
        var gridValue;
        
        switch(_value) {
            case 'disabled':
                gridValue = this.translation.gettext('disabled');
                break;
            case 'enabled':
              gridValue = this.translation.gettext('enabled');
              break;
              
            default:
              gridValue = String.format(this.translation.gettext('unknown status ({0})'), value);
              break;
        }
        
        return gridValue;
    },

    /**
     * creates the address grid
     * 
     */
    _showApplicationsGrid: function()
    {
        // if grid panel was allready created set active content panel and return
        if (this.gridPanel) {
            Tine.Tinebase.MainScreen.setActiveContentPanel(this.gridPanel, true);
            return;
        }
        
        var ctxMenuGrid = new Ext.menu.Menu({
            plugins: [{
                ptype: 'ux.itemregistry',
                key:   'Tinebase-MainContextMenu'
            }],
            items: [
                this._action_enable,
                this._action_disable,
                this._action_settings
            ]
        });

        
        var ds_applications = this._createApplicationaDataStore();
        
        var pagingToolbar = new Ext.PagingToolbar({ // inline paging toolbar
            pageSize: 50,
            store: ds_applications,
            displayInfo: true,
            displayMsg: this.translation.gettext('Displaying application {0} - {1} of {2}'),
            emptyMsg: this.translation.gettext("No applications to display")
        });
        
        var cm_applications = new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: [
                { header: this.translation.gettext('Order'),   id: 'order', dataIndex: 'order', width: 50},
                { header: this.translation.gettext('Name'),    id: 'name', dataIndex: 'name', renderer: this.translateAppTitle.createDelegate(this)},
                { header: this.translation.gettext('Status'),  id: 'status', dataIndex: 'status', width: 150, renderer: this._renderEnabled.createDelegate(this)},
                { header: this.translation.gettext('Version'), id: 'version', dataIndex: 'version', width: 70}
            ]
        });

        var rowSelectionModel = new Ext.grid.RowSelectionModel({multiSelect:true});
        
        rowSelectionModel.on('selectionchange', function(_selectionModel) {
            var rowCount = _selectionModel.getCount();
            var selected = _selectionModel.getSelections();

            if ( Tine.Tinebase.common.hasRight('manage', 'Admin', 'apps') ) {
                if (rowCount < 1) {
                    this._action_enable.setDisabled(true);
                    this._action_disable.setDisabled(true);
                    this._action_settings.setDisabled(true);
                } else if (rowCount > 1) {
                    this._action_enable.setDisabled(false);
                    this._action_disable.setDisabled(false);
                    this._action_settings.setDisabled(true);
                } else {
                    this._action_enable.setDisabled(false);
                    this._action_disable.setDisabled(false);
                    // check if app has admin panel and is enabled
                    if (Tine[selected[0].data.name] && Tine[selected[0].data.name].AdminPanel && selected[0].data.status == 'enabled') {
                        this._action_settings.setDisabled(false);
                    } else {
                        this._action_settings.setDisabled(true);
                    }
                }
                
                // don't allow to disable Admin, Tinebase or Addressbook as we can't deal with this yet
                for (var i=0; i<selected.length; i++) {
                    if (typeof selected[i].get == 'function' && selected[i].get('name').toString().match(/Tinebase|Admin|Addressbook/)) {
                        this._action_disable.setDisabled(true);
                        break;
                    }
                }
            }
        }, this);
                
        this.gridPanel = new Ext.grid.GridPanel({
            canonicalName: ['Application', 'Grid'].join(Tine.Tinebase.CanonicalPath.separator),
            store: ds_applications,
            cm: cm_applications,
            tbar: pagingToolbar,     
            autoSizeColumns: false,
            selModel: rowSelectionModel,
            enableColLock:false,
            autoExpandColumn: 'name',
            border: false,
            viewConfig: {
                /**
                 * Return CSS class to apply to rows depending upon flags
                 * - checks Flagged, Deleted and Seen
                 * 
                 * @param {Object} record
                 * @param {Integer} index
                 * @return {String}
                 */
                getRowClass: function(record, index) {
                    var className = '';
                    switch(record.get('status')) {
                        case 'disabled':
                            className = 'grid_row_disabled';
                            break;
                        case 'enabled':
                            className = 'grid_row_enabled';
                            break;
                    }
                    return className;
                }
            }
        });
        
        Tine.Tinebase.MainScreen.setActiveContentPanel(this.gridPanel, true);
        
        this.gridPanel.on('rowcontextmenu', function(_grid, _rowIndex, _eventObject) {
            _eventObject.stopEvent();
            if(!_grid.getSelectionModel().isSelected(_rowIndex)) {
                _grid.getSelectionModel().selectRow(_rowIndex);

                if ( Tine.Tinebase.common.hasRight('manage', 'Admin', 'apps') ) {
                    this._action_enable.setDisabled(false);
                    this._action_disable.setDisabled(false);
                }
                
                // don't allow to disable Admin, Tinebase or Addressbook as we can't deal with this yet
                if(_grid.getSelectionModel().getSelected().get('name').toString().match(/Tinebase|Admin|Addressbook/)) {
                    this._action_enable.setDisabled(true);
                    this._action_disable.setDisabled(true);
                }
            }
            ctxMenuGrid.showAt(_eventObject.getXY());
        }, this);
        
        this.gridPanel.on('rowdblclick', function(grid, index, e) {
            var record = grid.getStore().getAt(index);
            if (record.data.status == 'enabled' && Tine[record.data.name] && Tine[record.data.name].AdminPanel) {
                this._openSettingsWindow(record.data.name);
            }
        }, this);
    },

    show: function()
    {
        this.init();
        this._showApplicationsToolbar();
        this._showApplicationsGrid();

        this.loadData();
    },

    loadData: function()
    {
        var dataStore = this.gridPanel.getStore();
        dataStore.load({ params: { start:0, limit:50 } });
    },

    reload: function () {
        if (this.gridPanel) {
            this.gridPanel.getStore().reload.defer(200, this.gridPanel.getStore());
        }
    }
};


/***/ }),

/***/ 305:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
 */

/*global Ext, Tine*/ 

Ext.ns('Tine.Admin.user');

/**
 * Users 'mainScreen'
 * 
 * @static
 */
Tine.Admin.user.show = function () {
    var app = Tine.Tinebase.appMgr.get('Admin');
    if (! Tine.Admin.user.gridPanel) {
        Tine.Admin.user.gridPanel = new Tine.Admin.user.GridPanel({
            app: app
        });
    }
    else {
        Tine.Admin.user.gridPanel.loadGridData.defer(100, Tine.Admin.user.gridPanel, []);
    }

    app.getMainScreen().setActiveContentPanel(Tine.Admin.user.gridPanel, true);
    app.getMainScreen().setActiveToolbar(Tine.Admin.user.gridPanel.actionToolbar, true);
};


/************** models *****************/
Ext.ns('Tine.Admin.Model');

/**
 * Model of an account
 */
Tine.Admin.Model.UserArray = [
    { name: 'accountId' },
    { name: 'accountFirstName' },
    { name: 'accountLastName' },
    { name: 'accountLoginName' },
    { name: 'accountPassword' },
    { name: 'accountDisplayName' },
    { name: 'accountFullName' },
    { name: 'accountStatus' },
    { name: 'groups' },
    { name: 'accountRoles' },
    { name: 'accountPrimaryGroup' },
    { name: 'accountExpires', type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'accountLastLogin', type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'accountLastPasswordChange', type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'accountLastLoginfrom' },
    { name: 'accountEmailAddress' },
    { name: 'accountHomeDirectory' },
    { name: 'accountLoginShell' },
    { name: 'openid'},
    { name: 'visibility'},
    { name: 'sambaSAM' },
    { name: 'emailUser' },
    { name: 'contact_id' },
    { name: 'container_id' },
    { name: 'filesystemSize'},
    { name: 'effectiveAndLocalQuota'},
    { name: 'xprops'}
];

Tine.Admin.Model.User = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.genericFields.concat(Tine.Admin.Model.UserArray), {
    appName: 'Admin',
    modelName: 'User',
    idProperty: 'accountId',
    titleProperty: 'accountDisplayName',
    // ngettext('User', 'Users', n); gettext('Users');
    recordName: 'User',
    recordsName: 'Users'
});

/**
 * returns default account data
 * 
 * @namespace Tine.Admin.Model.User
 * @static
 * @return {Object} default data
 */
Tine.Admin.Model.User.getDefaultData = function () {
    var internalAddressbook = Tine.Admin.registry.get('defaultInternalAddressbook'),
        emailUserDefaults = (Tine.Admin.registry.get('config').defaultImapUserSettings && Tine.Admin.registry.get('config').defaultImapUserSettings.value)
            ? Tine.Admin.registry.get('config').defaultImapUserSettings.value : '';
        
    return {
        sambaSAM: '',
        emailUser: emailUserDefaults,
        accountStatus: 'enabled',
        visibility: (internalAddressbook !== null) ? 'displayed' : 'hidden',
        container_id: internalAddressbook,
        accountPrimaryGroup: Tine.Admin.registry.get('defaultPrimaryGroup')
    };
};

Tine.Admin.Model.SAMUserArray = [
    { name: 'sid'              },
    { name: 'primaryGroupSID'  },
    { name: 'acctFlags'        },
    { name: 'homeDrive'        },
    { name: 'homePath'         },
    { name: 'profilePath'      },
    { name: 'logonScript'      },
    { name: 'logonTime',     type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'logoffTime',    type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'kickoffTime',   type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'pwdLastSet',    type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'pwdCanChange',  type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'pwdMustChange', type: 'date', dateFormat: Date.patterns.ISO8601Long }
];

Tine.Admin.Model.SAMUser = Tine.Tinebase.data.Record.create(Tine.Admin.Model.SAMUserArray, {
    appName: 'Admin',
    modelName: 'SAMUser',
    idProperty: 'sid',
    titleProperty: null,
    // ngettext('Samba User', 'Samba Users', n);
    recordName: 'Samba User',
    recordsName: 'Samba Users'
});

Tine.Admin.Model.EmailUserArray = [
    { name: 'emailUID' },
    { name: 'emailGID' },
    { name: 'emailMailQuota' },
    { name: 'emailMailSize' },
    { name: 'emailSieveQuota' },
    { name: 'emailSieveSize' },
    { name: 'emailLastLogin', type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'emailUserId' },
    { name: 'emailAliases' },
    { name: 'emailForwards' },
    { name: 'emailForwardOnly' },
    { name: 'emailAddress' },
    { name: 'emailUsername' }
];

Tine.Admin.Model.EmailUser = Tine.Tinebase.data.Record.create(Tine.Admin.Model.EmailUserArray, {
    appName: 'Admin',
    modelName: 'EmailUser',
    idProperty: 'sid',
    titleProperty: null,
    // ngettext('Email User', 'Email Users', n);
    recordName: 'Email User',
    recordsName: 'Email Users'
});




/************** backends *****************/

Tine.Admin.userBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'User',
    recordClass: Tine.Admin.Model.User,
    idProperty: 'accountId'
});

Tine.Admin.samUserBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'SAMUser',
    recordClass: Tine.Admin.Model.SAMUser,
    idProperty: 'sid'
});

Tine.Admin.emailUserBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'EmailUser',
    recordClass: Tine.Admin.Model.EmailUser,
    idProperty: 'emailUID'
});

Tine.Admin.sharedAddressbookBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'SharedAddressbook',
    recordClass: Tine.Tinebase.Model.Container,
    idProperty: 'id'
});


/***/ }),

/***/ 306:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */
Ext.ns('Tine.Admin.user');


/**
 * User grid panel
 * 
 * @namespace   Tine.Admin.user
 * @class       Tine.Admin.user.GridPanel
 * @extends     Tine.widgets.grid.GridPanel
 */
Tine.Admin.user.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    /**
     * @property isLdapBackend
     * @type Boolean
     */
    isLdapBackend: false,
    
    newRecordIcon: 'action_addContact',
    recordClass: Tine.Admin.Model.User,
    recordProxy: Tine.Admin.userBackend,
    defaultSortInfo: {field: 'accountLoginName', direction: 'ASC'},
    evalGrants: false,
    gridConfig: {
        id: 'gridAdminUsers',
        autoExpandColumn: 'accountDisplayName'
    },
    
    initComponent: function() {
        this.gridConfig.cm = this.getColumnModel();
        this.isLdapBackend = Tine.Tinebase.registry.get('accountBackend') == 'Ldap';
        this.isEmailBackend = Tine.Tinebase.registry.get('manageImapEmailUser');
        Tine.Admin.user.GridPanel.superclass.initComponent.call(this);
    },
    
    /**
     * init actions with actionToolbar, contextMenu and actionUpdater
     * 
     * @private
     */
    initActions: function() {
        this.actionEnable = new Ext.Action({
            requiredGrant: 'readGrant',
            text: this.app.i18n._('Enable Account'),
            allowMultiple: true,
            disabled: true,
            handler: this.enableDisableButtonHandler.createDelegate(this, ['enabled']),
            iconCls: 'action_enable',
            actionUpdater: this.enableDisableActionUpdater.createDelegate(this, [['disabled', 'blocked', 'expired']], true)
        });
    
        this.actionDisable = new Ext.Action({
            requiredGrant: 'readGrant',
            text: this.app.i18n._('Disable Account'),
            allowMultiple: true,
            disabled: true,
            handler: this.enableDisableButtonHandler.createDelegate(this, ['disabled']),
            iconCls: 'action_disable',
            actionUpdater: this.enableDisableActionUpdater.createDelegate(this, [['enabled']], true)
        });
    
        this.actionResetPassword = new Ext.Action({
            requiredGrant: 'readGrant',
            text: this.app.i18n._('Reset Password'),
            disabled: true,
            handler: this.resetPasswordHandler,
            iconCls: 'action_password',
            scope: this
        });

        this.actionResetPin = new Ext.Action({
            requiredGrant: 'readGrant',
            text: this.app.i18n._('Reset Pin'),
            disabled: true,
            handler: this.resetPinHandler,
            iconCls: 'action_password',
            hidden: ! (Tine.Tinebase.registry.get('config').userPin && Tine.Tinebase.registry.get('config').userPin.value),
            scope: this
        });

        this.actionUpdater.addActions([
            this.actionEnable,
            this.actionDisable,
            this.actionResetPassword,
            this.actionResetPin
        ]);
        
        Tine.Admin.user.GridPanel.superclass.initActions.call(this);
    },
    
    /**
     * initialises filter toolbar
     */
    initFilterPanel: function() {
        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
            filterModels: [
                {label: this.app.i18n.n_('User', 'Users', 1),    field: 'query',       operators: ['contains']}
                //{label: this.app.i18n._('Description'),    field: 'description', operators: ['contains']},
            ],
            defaultFilter: 'query',
            filters: [],
            plugins: [
                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
            ]
        });
        this.plugins = this.plugins || [];
        this.plugins.push(this.filterToolbar);
    },
    
    /**
     * add custom items to action toolbar
     * 
     * @return {Object}
     */
    getActionToolbarItems: function() {
        return [
            Ext.apply(new Ext.Button(this.actionEnable), {
                scale: 'medium',
                rowspan: 2,
                iconAlign: 'top'
            }),
            Ext.apply(new Ext.Button(this.actionDisable), {
                scale: 'medium',
                rowspan: 2,
                iconAlign: 'top'
            }),
            Ext.apply(new Ext.Button(this.actionResetPassword), {
                scale: 'medium',
                rowspan: 2,
                iconAlign: 'top'
            }),
            Ext.apply(new Ext.Button(this.actionResetPin), {
                scale: 'medium',
                rowspan: 2,
                iconAlign: 'top'
            })
        ];
    },
    
    /**
     * add custom items to context menu
     * 
     * @return {Array}
     */
    getContextMenuItems: function() {
        var items = [
            '-',
            this.actionEnable,
            this.actionDisable,
            '-',
            this.actionResetPassword,
            this.actionResetPin
        ];
        
        return items;
    },
    
    /**
     * returns column model
     * 
     * @return Ext.grid.ColumnModel
     * @private
     */
    getColumnModel: function() {
        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                hidden: true,
                resizable: true
            },
            columns: this.getColumns()
        });
    },
    
    /**
     * returns columns
     * @private
     * @return Array
     */
    getColumns: function(){
        return [
            { header: this.app.i18n._('ID'), id: 'accountId', dataIndex: 'accountId', width: 50},
            { header: this.app.i18n._('Status'), id: 'accountStatus', dataIndex: 'accountStatus', hidden: this.isLdapBackend, width: 50, renderer: this.statusRenderer},
            { header: this.app.i18n._('Display name'), id: 'accountDisplayName', dataIndex: 'accountDisplayName', hidden: false},
            { header: this.app.i18n._('Login name'), id: 'accountLoginName', dataIndex: 'accountLoginName', width: 160, hidden: false},
            { header: this.app.i18n._('Last name'), id: 'accountLastName', dataIndex: 'accountLastName'},
            { header: this.app.i18n._('First name'), id: 'accountFirstName', dataIndex: 'accountFirstName'},
            { header: this.app.i18n._('Email'), id: 'accountEmailAddress', dataIndex: 'accountEmailAddress', width: 200, hidden: false},
            { header: this.app.i18n._('Email usage'), id: 'emailQuota', hidden: this.isEmailBackend, dataIndex: 'emailUser', renderer: this.emailQuotaRenderer, sortable: false},
            { header: this.app.i18n._('Filesystem usage'), id: 'fileQuota', dataIndex: 'filesystemSize', renderer: this.fileQuotaRenderer, hidden: false, sortable: false},
            { header: this.app.i18n._('OpenID'), id: 'openid', dataIndex: 'openid', width: 200},
            { header: this.app.i18n._('Last login at'), id: 'accountLastLogin', dataIndex: 'accountLastLogin', hidden: this.isLdapBackend, width: 140, renderer: Tine.Tinebase.common.dateTimeRenderer},
            { header: this.app.i18n._('Last login from'), id: 'accountLastLoginfrom', hidden: this.isLdapBackend, dataIndex: 'accountLastLoginfrom'},
            { header: this.app.i18n._('Password changed'), id: 'accountLastPasswordChange', dataIndex: 'accountLastPasswordChange', width: 140, renderer: Tine.Tinebase.common.dateTimeRenderer, hidden: false},
            { header: this.app.i18n._('Expires'), id: 'accountExpires', dataIndex: 'accountExpires', width: 140, renderer: Tine.Tinebase.common.dateTimeRenderer, hidden: false}
        ].concat(this.getModlogColumns());
    },
    
    enableDisableButtonHandler: function(status) {
        var accountIds = new Array();
        var selectedRows = this.grid.getSelectionModel().getSelections();
        for (var i = 0; i < selectedRows.length; ++i) {
            accountIds.push(selectedRows[i].id);
        }
        
        Ext.Ajax.request({
            url : 'index.php',
            method : 'post',
            params : {
                method : 'Admin.setAccountState',
                accountIds : accountIds,
                status: status
            },
            scope: this,
            callback : function(_options, _success, _response) {
                if(_success === true) {
                    var result = Ext.util.JSON.decode(_response.responseText);
                    if(result.success === true) {
                        this.loadGridData({
                            removeStrategy: 'keepBuffered'
                        });
                    }
                }
            }
        });
    },
    
    /**
     * updates enable/disable actions
     * 
     * @param {Ext.Action} action
     * @param {Object} grants grants sum of grants
     * @param {Object} records
     * @param {Boolean} isFilterSelect
     * @param {Array} requiredAccountStatus
     */
    enableDisableActionUpdater: function(action, grants, records, isFilterSelect, requiredAccountStatus) {
        var enabled = records.length > 0;
        Ext.each(records, function(record){
            enabled &= requiredAccountStatus.indexOf(record.get('accountStatus')) >=0;// === requiredAccountStatus;
            return enabled;
        }, this);
        
        action.setDisabled(!enabled);
    },
    
    /**
     * reset password
     * 
     * TODO add checkbox for must change pw
     * TODO add pw repeat (see user edit dialog)
     */
    resetPasswordHandler: function(_button, _event) {
        Ext.MessageBox.prompt(this.app.i18n._('Set new password'), this.app.i18n._('Please enter the new password:'), function(_button, _text) {
            if(_button == 'ok') {
                var accountObject = this.grid.getSelectionModel().getSelected().data;
                
                Ext.Ajax.request( {
                    params: {
                        method    : 'Admin.resetPassword',
                        account   : accountObject,
                        password  : _text,
                        mustChange: false
                    },
                    scope: this,
                    callback : function(_options, _success, _response) {
                        if(_success === true) {
                            var result = Ext.util.JSON.decode(_response.responseText);
                            if(result.success === true) {
                                this.grid.getStore().reload();
                            }
                        } else {
                            Tine.Tinebase.ExceptionHandler.handleRequestException(_response);
                        }
                    }
                });
            }
        }, this);
    },

    resetPinHandler: function(_button, _event) {
        Ext.MessageBox.prompt(this.app.i18n._('Set new pin'), this.app.i18n._('Please enter the new pin:'), function(_button, _text) {
            if(_button == 'ok') {
                var accountObject = this.grid.getSelectionModel().getSelected().data;

                Ext.Ajax.request( {
                    params: {
                        method    : 'Admin.resetPin',
                        account   : accountObject,
                        password  : _text
                    },
                    scope: this,
                    callback : function(_options, _success, _response) {
                        if(_success === true) {
                            var result = Ext.util.JSON.decode(_response.responseText);
                            if(result.success === true) {
                                this.grid.getStore().reload();
                            }
                        } else {
                            Tine.Tinebase.ExceptionHandler.handleRequestException(_response);
                        }
                    }
                });
            }
        }, this);
    },
    
    statusRenderer: function (_value, _cellObject, _record, _rowIndex, _colIndex, _dataStore) {
        var gridValue;
        
        switch(_value) {
            case 'blocked':
                gridValue = "<img src='images/oxygen/16x16/status/security-medium.png' width='16' height='16'/>";
                break;

            case 'enabled':
                gridValue = "<img src='images/icon-set/icon_ok.svg' width='16' height='16'/>";
                break;

            case 'disabled':
                gridValue = "<img src='images/icon-set/icon_stop.svg' width='16' height='16'/>";
                break;

            case 'expired':
                gridValue = "<img src='images/oxygen/16x16/status/user-away.png' width='16' height='16'/>";
                break;

            default:
                gridValue = _value;
                break;
        }
        
        return gridValue;
    },

    emailQuotaRenderer: function(_value) {
        var quota = _value['emailMailQuota'] ? _value['emailMailQuota'] : 0,
            size = _value['emailMailSize'] ? _value['emailMailSize'] : 0;

        return Tine.widgets.grid.QuotaRenderer(size, quota, /*use SoftQuota*/ false);
    },

    fileQuotaRenderer: function(_value, _cellObject, _record) {
        var accountConfig = _record.get('xprops') ? _record.get('xprops') : null,
            quotaConfig = Tine.Tinebase.configManager.get('quota'),
            quota = accountConfig && accountConfig['personalFSQuota'] ? parseInt(accountConfig['personalFSQuota'])  : quotaConfig.totalByUserInMB * 1024 * 1024,
            size =  _record.get('filesystemSize') ? parseInt(_record.get('filesystemSize')) : 0;

        return Tine.widgets.grid.QuotaRenderer(size, quota, /*use SoftQuota*/ true);
    }
});


/***/ }),

/***/ 307:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2009-2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */
 
/*global Ext, Tine*/

Ext.ns('Tine.Admin.user');

/**
 * @namespace   Tine.Admin.user
 * @class       Tine.Admin.UserEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * NOTE: this class doesn't use the user namespace as this is not yet supported by generic grid
 * 
 * <p>User Edit Dialog</p>
 * <p>
 * </p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Admin.UserEditDialog
 */
Tine.Admin.UserEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    windowNamePrefix: 'userEditWindow_',
    appName: 'Admin',
    recordClass: Tine.Admin.Model.User,
    recordProxy: Tine.Admin.userBackend,
    evalGrants: false,
    
    /**
     * @private
     */
    initComponent: function () {
        var accountBackend = Tine.Tinebase.registry.get('accountBackend');
        this.ldapBackend = (accountBackend === 'Ldap' || accountBackend === 'ActiveDirectory');

        Tine.Admin.UserEditDialog.superclass.initComponent.call(this);
    },

    /**
     * @private
     */
    onRecordLoad: function () {
        // interrupt process flow until dialog is rendered
        if (! this.rendered) {
            this.onRecordLoad.defer(250, this);
            return;
        }
        
        // samba user
        var response = {
            responseText: Ext.util.JSON.encode(this.record.get('sambaSAM'))
        };
        this.samRecord = Tine.Admin.samUserBackend.recordReader(response);
        // email user
        var emailResponse = {
            responseText: Ext.util.JSON.encode(this.record.get('emailUser'))
        };
        this.emailRecord = Tine.Admin.emailUserBackend.recordReader(emailResponse);
        
        // format dates
        var dateTimeDisplayFields = ['accountLastLogin', 'accountLastPasswordChange', 'logonTime', 'logoffTime', 'pwdLastSet'];
        for (var i = 0; i < dateTimeDisplayFields.length; i += 1) {
            if (dateTimeDisplayFields[i] === 'accountLastLogin' || dateTimeDisplayFields[i] === 'accountLastPasswordChange') {
                this.record.set(dateTimeDisplayFields[i], Tine.Tinebase.common.dateTimeRenderer(this.record.get(dateTimeDisplayFields[i])));
            } else {
                this.samRecord.set(dateTimeDisplayFields[i], Tine.Tinebase.common.dateTimeRenderer(this.samRecord.get(dateTimeDisplayFields[i])));
            }
        }

        this.getForm().loadRecord(this.emailRecord);
        this.getForm().loadRecord(this.samRecord);
        this.record.set('sambaSAM', this.samRecord.data);

        if (Tine.Admin.registry.get('manageSmtpEmailUser')) {
            if (this.emailRecord.get('emailAliases')) {
                this.aliasesGrid.setStoreFromArray(this.emailRecord.get('emailAliases'));
            }
            if (this.emailRecord.get('emailForwards')) {
                this.forwardsGrid.setStoreFromArray(this.emailRecord.get('emailForwards'));
            }
        }
        if (Tine.Admin.registry.get('manageImapEmailUser')) {
            if (!this.emailRecord.get('emailMailQuota')) this.getForm().findField('emailMailQuota').setValue(null);
        }

        // load stores for memberships
        if (this.record.id) {
            this.storeGroups.loadData(this.record.get('groups'));
            this.storeRoles.loadData(this.record.get('accountRoles'));
        }

        var fileSystem = this.record.get('effectiveAndLocalQuota');
        if (fileSystem && fileSystem.localUsage) {
            this.getForm().findField('personalFSSize').setValue(parseInt(fileSystem.localUsage));
        }

        var xprops = this.record.get('xprops');
        xprops = Ext.isObject(xprops) ? xprops : {};
        if (xprops.personalFSQuota) {
            this.getForm().findField('personalFSQuota').setValue(xprops.personalFSQuota);
        }

        Tine.Admin.UserEditDialog.superclass.onRecordLoad.call(this);
    },
    
    /**
     * @private
     */
    onRecordUpdate: function () {
        Tine.Admin.UserEditDialog.superclass.onRecordUpdate.call(this);
        
        Tine.log.debug('Tine.Admin.UserEditDialog::onRecordUpdate()');
        
        var form = this.getForm();
        form.updateRecord(this.samRecord);
        if (this.samRecord.dirty) {
            // only update sam record if something changed
            this.unsetLocalizedDateTimeFields(this.samRecord, ['logonTime', 'logoffTime', 'pwdLastSet']);
            this.record.set('sambaSAM', '');
            this.record.set('sambaSAM', this.samRecord.data);
        }

        form.updateRecord(this.emailRecord);
        // get aliases / forwards
        if (Tine.Admin.registry.get('manageSmtpEmailUser')) {
            // forcing blur of quickadd grids
            this.aliasesGrid.doBlur();
            this.forwardsGrid.doBlur();
            this.emailRecord.set('emailAliases', this.aliasesGrid.getFromStoreAsArray());
            this.emailRecord.set('emailForwards', this.forwardsGrid.getFromStoreAsArray());
            Tine.log.debug('Tine.Admin.UserEditDialog::onRecordUpdate() -> setting aliases and forwards in email record');
            Tine.log.debug(this.emailRecord);
        }
        this.unsetLocalizedDateTimeFields(this.emailRecord, ['emailLastLogin']);
        this.record.set('emailUser', '');
        this.record.set('emailUser', this.emailRecord.data);
        
        var newGroups = [],
            newRoles = [];
        
        this.storeGroups.each(function (rec) {
            newGroups.push(rec.data.id);
        });
        // add selected primary group to new groups if not exists
        if (newGroups.indexOf(this.record.get('accountPrimaryGroup')) === -1) {
            newGroups.push(this.record.get('accountPrimaryGroup'));
        }
         
        this.storeRoles.each(function (rec) {
            newRoles.push(rec.data.id);
        });
        
        this.record.set('groups', newGroups);
        this.record.set('accountRoles', newRoles);
        
        this.unsetLocalizedDateTimeFields(this.record, ['accountLastLogin', 'accountLastPasswordChange']);

        var xprops = {};
        xprops.personalFSQuota = this.getForm().findField('personalFSQuota').getValue();
        Tine.Tinebase.common.assertComparable(xprops);
        this.record.set('xprops', xprops);
    },
    
    /**
     * need to unset localized datetime fields before saving
     * 
     * @param {Object} record
     * @param {Array} dateTimeDisplayFields
     */
    unsetLocalizedDateTimeFields: function(record, dateTimeDisplayFields) {
        Ext.each(dateTimeDisplayFields, function (dateTimeDisplayField) {
            record.set(dateTimeDisplayField, '');
        }, this);
    },

    /**
     * is form valid?
     * 
     * @return {Boolean}
     */
    isValid: function() {
        var result = Tine.Admin.UserEditDialog.superclass.isValid.call(this);
        if (! result) {
            return false;
        }
        
        if (Tine.Admin.registry.get('manageSmtpEmailUser')) {
            var emailValue = this.getForm().findField('accountEmailAddress').getValue();
            if (! this.checkEmailDomain(emailValue)) {
                result = false;
                this.getForm().markInvalid([{
                    id: 'accountEmailAddress',
                    msg: this.app.i18n._("Domain is not allowed. Check your SMTP domain configuration.")
                }]);
            }
        }

        if (Tine.Tinebase.appMgr.get('Admin').featureEnabled('featurePreventSpecialCharInLoginName')) {
            if (! this.validateLoginName(this.getForm().findField('accountLoginName').getValue())) {
                result = false;
                this.getForm().markInvalid([{
                    id: 'accountLoginName',
                    msg: this.app.i18n._("Special characters are not allowed in login name.")
                }]);
            }
        }
        
        return result;
    },
    
    /**
     * check valid email domain (if email domain is set in config)
     * 
     * @param {String} email
     * @return {Boolean}
     * 
     * TODO use this for smtp aliases, too
     */
    checkEmailDomain: function(email) {
        if (! Tine.Admin.registry.get('primarydomain') || ! email) {
            return true;
        }
        
        var allowedDomains = [Tine.Admin.registry.get('primarydomain')],
            emailDomain = email.split('@')[1];
            
        if (Ext.isString(Tine.Admin.registry.get('secondarydomains'))) {
            allowedDomains = allowedDomains.concat(Tine.Admin.registry.get('secondarydomains').split(','));
        }
        
        return (allowedDomains.indexOf(emailDomain) !== -1);
    },
    
    /**
     * Validate confirmed password
     */
    onPasswordConfirm: function () {
        var confirmForm = this.passwordConfirmWindow.items.first().getForm(),
            confirmValues = confirmForm.getValues(),
            passwordStatus = confirmForm.findField('passwordStatus'),
            passwordField = (this.getForm()) ? this.getForm().findField('accountPassword') : null;
        
        if (! passwordField) {
            // oops: something went wrong, this should not happen
            return false;
        }
        
        if (confirmValues.passwordRepeat !== passwordField.getValue()) {
            passwordStatus.el.setStyle('color', 'red');
            passwordStatus.setValue(this.app.i18n.gettext('Passwords do not match!'));
            
            passwordField.passwordsMatch = false;
            passwordField.markInvalid(this.app.i18n.gettext('Passwords do not match!'));
        } else {
            passwordStatus.el.setStyle('color', 'green');
            passwordStatus.setValue(this.app.i18n.gettext('Passwords match!'));
                        
            passwordField.passwordsMatch = true;
            passwordField.clearInvalid();
        }
        
        return passwordField.passwordsMatch ? passwordField.passwordsMatch : passwordStatus.getValue();
    },
    
    /**
     * Get current primary group (selected from combobox or default primary group)
     * 
     * @return {String} - id of current primary group
     */
    getCurrentPrimaryGroupId: function () {
        return this.getForm().findField('accountPrimaryGroup').getValue() || this.record.get('accountPrimaryGroup').id;
    },
    
    /**
     * Init User groups picker grid
     * 
     * @return {Tine.widgets.account.PickerGridPanel}
     */
    initUserGroups: function () {
        this.storeGroups = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Admin.Model.Group
        });
        
        var self = this;
        
        this.pickerGridGroups = new Tine.widgets.account.PickerGridPanel({
            border: false,
            frame: false,
            store: this.storeGroups,
            selectType: 'group',
            selectAnyone: false,
            selectTypeDefault: 'group',
            groupRecordClass: Tine.Admin.Model.Group,
            getColumnModel: function () {
                return new Ext.grid.ColumnModel({
                    defaults: { sortable: true },
                    columns:  [
                        {id: 'name', header: self.app.i18n._('Name'), dataIndex: this.recordPrefix + 'name', renderer: function (val, meta, record) {
                            return record.data.id === self.getCurrentPrimaryGroupId() ? (record.data.name + '<span class="x-item-disabled"> (' + self.app.i18n.gettext('Primary group') + ')<span>') : record.data.name;
                        }}
                    ]
                });
            }
        });
        // disable remove of group if equal to current primary group
        this.pickerGridGroups.selModel.on('beforerowselect', function (sm, index, keep, record) {
            if (record.data.id === this.getCurrentPrimaryGroupId()) {
                return false;
            }
        }, this);
        
        return this.pickerGridGroups;
    },
    
    /**
     * Init User roles picker grid
     * 
     * @return {Tine.widgets.account.PickerGridPanel}
     */
    initUserRoles: function () {
        this.storeRoles = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Tinebase.Model.Role
        });
        
        this.pickerGridRoles = new Tine.widgets.grid.PickerGridPanel({
            border: false,
            frame: false,
            autoExpandColumn: 'name',
            store: this.storeRoles,
            recordClass: Tine.Tinebase.Model.Role,
            columns: [{id: 'name', header: this.app.i18n.gettext('Name'), sortable: true, dataIndex: 'name'}],
            initActionsAndToolbars: function () {
                // for now removed abillity to edit role membership
//                Tine.widgets.grid.PickerGridPanel.prototype.initActionsAndToolbars.call(this);
//                
//                this.comboPanel = new Ext.Container({
//                    layout: 'hfit',
//                    border: false,
//                    items: this.getSearchCombo(),
//                    columnWidth: 1
//                });
//                
//                this.tbar = new Ext.Toolbar({
//                    items: this.comboPanel,
//                    layout: 'column'
//                });
            },
            onAddRecordFromCombo: function (recordToAdd) {
                // check if already in
                if (! this.recordStore.getById(recordToAdd.id)) {
                    this.recordStore.add([recordToAdd]);
                }
                this.collapse();
                this.clearValue();
                this.reset();
            }
        });
        // remove listeners for this grid selection model
        this.pickerGridRoles.selModel.purgeListeners();
        
        return this.pickerGridRoles;
    },
    
    /**
     * Init Fileserver tab items
     * 
     * @return {Array} - array ff fileserver tab items
     */
    initFileserver: function () {
        if (this.ldapBackend) {
            return [{
                xtype: 'fieldset',
                title: this.app.i18n.gettext('Unix'),
                autoHeight: true,
                checkboxToggle: false,
                layout: 'hfit',
                items: [{
                    xtype: 'columnform',
                    labelAlign: 'top',
                    formDefaults: {
                        xtype: 'textfield',
                        anchor: '100%',
                        labelSeparator: '',
                        columnWidth: 0.333
                    },
                    items: [[{
                        fieldLabel: this.app.i18n.gettext('Home Directory'),
                        name: 'accountHomeDirectory',
                        columnWidth: 0.666
                    }, {
                        fieldLabel: this.app.i18n.gettext('Login Shell'),
                        name: 'accountLoginShell'
                    }]]
                }]
            }, {
                xtype: 'fieldset',
                title: this.app.i18n.gettext('Windows'),
                autoHeight: true,
                checkboxToggle: false,
                layout: 'hfit',
                items: [{
                    xtype: 'columnform',
                    labelAlign: 'top',
                    formDefaults: {
                        xtype: 'textfield',
                        anchor: '100%',
                        labelSeparator: '',
                        columnWidth: 0.333
                    },
                    items: [[{
                        fieldLabel: this.app.i18n.gettext('Home Drive'),
                        name: 'homeDrive',
                        columnWidth: 0.666
                    }, {
                        xtype: 'displayfield',
                        fieldLabel: this.app.i18n.gettext('Logon Time'),
                        name: 'logonTime',
                        emptyText: this.app.i18n.gettext('never logged in'),
                        style: this.displayFieldStyle
                    }], [{
                        fieldLabel: this.app.i18n.gettext('Home Path'),
                        name: 'homePath',
                        columnWidth: 0.666
                    }, {
                        xtype: 'displayfield',
                        fieldLabel: this.app.i18n.gettext('Logoff Time'),
                        name: 'logoffTime',
                        emptyText: this.app.i18n.gettext('never logged off'),
                        style: this.displayFieldStyle
                    }], [{
                        fieldLabel: this.app.i18n.gettext('Profile Path'),
                        name: 'profilePath',
                        columnWidth: 0.666
                    }, {
                        xtype: 'displayfield',
                        fieldLabel: this.app.i18n.gettext('Password Last Set'),
                        name: 'pwdLastSet',
                        emptyText: this.app.i18n.gettext('never'),
                        style: this.displayFieldStyle
                    }], [{
                        fieldLabel: this.app.i18n.gettext('Logon Script'),
                        name: 'logonScript',
                        columnWidth: 0.666
                    }], [{
                        xtype: 'extuxclearabledatefield',
                        fieldLabel: this.app.i18n.gettext('Password Can Change'),
                        name: 'pwdCanChange',
                        emptyText: this.app.i18n.gettext('not set')
                    }, {
                        xtype: 'extuxclearabledatefield',
                        fieldLabel: this.app.i18n.gettext('Password Must Change'),
                        name: 'pwdMustChange',
                        emptyText: this.app.i18n.gettext('not set')
                    }, {
                        xtype: 'extuxclearabledatefield',
                        fieldLabel: this.app.i18n.gettext('Kick Off Time'),
                        name: 'kickoffTime',
                        emptyText: this.app.i18n.gettext('not set')
                    }]]
                }]
            }];
        }
        
        return [];
    },

    /**
     * Init Filesystem tab items
     *
     * @return {Array} - array of tab items
     */
    initFilesystem: function () {
        return [{
            xtype: 'fieldset',
            title: this.app.i18n.gettext('Filesystem Quota'),
            autoHeight: true,
            checkboxToggle: true,
            layout: 'hfit',
            listeners: {
                scope: this,
                collapse: function () {
                    this.getForm().findField('personalQuota').setValue(null);
                }
            },
            items: [{
                xtype: 'columnform',
                labelAlign: 'top',
                formDefaults: {
                    xtype: 'textfield',
                    anchor: '100%',
                    columnWidth: 0.666
                },
                items: [[{
                    fieldLabel: this.app.i18n.gettext('Quota'),
                    emptyText: this.app.i18n.gettext('no quota set'),
                    name: 'personalFSQuota',
                    xtype: 'extuxbytesfield'
                }], [{
                    fieldLabel: this.app.i18n.gettext('Current Filesystem usage'),
                    name: 'personalFSSize',
                    xtype: 'extuxbytesfield',
                    disabled: true
                }]]
            }]
        }];
    },

    /**
     * Init IMAP tab items
     * 
     * @return {Array} - array of IMAP tab items
     */
    initImap: function () {
        if (Tine.Admin.registry.get('manageImapEmailUser')) {
            return [{
                xtype: 'fieldset',
                title: this.app.i18n.gettext('IMAP Quota'),
                autoHeight: true,
                checkboxToggle: true,
                layout: 'hfit',
                listeners: {
                    scope: this,
                    collapse: function() {
                        this.getForm().findField('emailMailQuota').setValue(null);
                    }
                },
                items: [{
                    xtype: 'columnform',
                    labelAlign: 'top',
                    formDefaults: {
                        xtype: 'textfield',
                        anchor: '100%',
                        columnWidth: 0.666
                    },
                    items: [[{
                        fieldLabel: this.app.i18n.gettext('Quota'),
                        emptyText: this.app.i18n.gettext('no quota set'),
                        name: 'emailMailQuota',
                        xtype: 'extuxbytesfield'
                    }], [{
                        fieldLabel: this.app.i18n.gettext('Current Mailbox size'),
                        name: 'emailMailSize',
                        xtype: 'extuxbytesfield',
                        disabled: true
                    }]]
                }]
            }, {
                xtype: 'fieldset',
                title: this.app.i18n.gettext('Sieve Quota'),
                autoHeight: true,
                checkboxToggle: true,
                layout: 'hfit',
                listeners: {
                    scope: this,
                    collapse: function() {
                        this.getForm().findField('emailSieveQuota').setValue(null);
                    }
                },
                items: [{
                    xtype: 'columnform',
                    labelAlign: 'top',
                    formDefaults: {
                        xtype: 'textfield',
                        anchor: '100%',
                        columnWidth: 0.666
                    },
                    items: [[{
                        fieldLabel: this.app.i18n.gettext('Quota'),
                        emptyText: this.app.i18n.gettext('no quota set'),
                        name: 'emailSieveQuota',
                        xtype: 'extuxbytesfield'
                    }], [{
                        fieldLabel: this.app.i18n.gettext('Current Sieve size'),
                        name: 'emailSieveSize',
                        xtype: 'extuxbytesfield',
                        disabled: true
                    }]
                    ]
                }]
            }, {
                xtype: 'fieldset',
                title: this.app.i18n.gettext('Information'),
                autoHeight: true,
                checkboxToggle: false,
                layout: 'hfit',
                items: [{
                    xtype: 'columnform',
                    labelAlign: 'top',
                    formDefaults: {
                        xtype: 'displayfield',
                        anchor: '100%',
                        columnWidth: 0.666,
                        style: this.displayFieldStyle
                    },
                    items: [[{
                        fieldLabel: this.app.i18n.gettext('Last Login'),
                        name: 'emailLastLogin'
                    }]]
                }]
            }];
        }
        
        return [];
    },
    
    /**
     * @private
     * 
     * init email grids
     * @return Array
     * 
     * TODO     add ctx menu
     */
    initSmtp: function () {
        if (! Tine.Admin.registry.get('manageSmtpEmailUser')) {
            return [];
        }
        
        var commonConfig = {
            autoExpandColumn: 'email',
            quickaddMandatory: 'email',
            frame: false,
            useBBar: true,
            dataField: 'email',
            height: 200,
            columnWidth: 0.5,
            recordClass: Ext.data.Record.create([
                { name: 'email' }
            ])
        };
        
        // TODO how to fetch smtp config if Felamimail isn't installed?
        var smtpPrimarydomain = Tine.Admin.registry.get('primarydomain');
        var smtpSecondarydomains = Tine.Admin.registry.get('secondarydomains');

        var domains = (smtpSecondarydomains && smtpSecondarydomains.length) ? smtpSecondarydomains.split(',') : [];
        if (smtpPrimarydomain.length) {
            domains.push(smtpPrimarydomain);
        }
        var app = this.app,
            record = this.record;
            
        this.aliasesGrid = new Tine.widgets.grid.QuickaddGridPanel(
            Ext.apply({
                onNewentry: function(value) {
                    var split = value.email ? value.email.split('@') : [];
                    if (split.length != 2 || split[1].split('.').length < 2) {
                        return false;
                    }
                    var domain = split[1];
                    if (domains.indexOf(domain) > -1) {
                        Tine.widgets.grid.QuickaddGridPanel.prototype.onNewentry.call(this, value);
                    } else {
                        Ext.MessageBox.show({
                            buttons: Ext.Msg.OK,
                            icon: Ext.MessageBox.WARNING,
                            title: app.i18n._('Domain not allowed'),
                            msg: String.format(app.i18n._('The domain {0} of the alias {1} you tried to add is neither configured as primary domain nor set as a secondary domain in the setup.'
                                + ' Please add this domain to the secondary domains in SMTP setup or use another domain which is configured already.'),
                                '<b>' + domain + '</b>', '<b>' + value.email + '</b>')
                        });
                        return false;
                    }
                },
                cm: new Ext.grid.ColumnModel([{
                    id: 'email', 
                    header: this.app.i18n.gettext('Email Alias'),
                    dataIndex: 'email', 
                    width: 300, 
                    hideable: false, 
                    sortable: true,
                    quickaddField: new Ext.form.TextField({
                        emptyText: this.app.i18n.gettext('Add an alias address...'),
                        vtype: 'email'
                    }),
                    editor: new Ext.form.TextField({allowBlank: false})
                }])
            }, commonConfig)
        );
        this.aliasesGrid.render(document.body);
        
        var aliasesStore = this.aliasesGrid.getStore();

        this.forwardsGrid = new Tine.widgets.grid.QuickaddGridPanel(
            Ext.apply({
                onNewentry: function(value) {
                    if (value.email === record.get('accountEmailAddress') || aliasesStore.find('email', value.email) !== -1) {
                        Ext.MessageBox.show({
                            buttons: Ext.Msg.OK,
                            icon: Ext.MessageBox.WARNING,
                            title: app.i18n._('Forwarding to self'),
                            msg: app.i18n._('You are not allowed to set a forward email address that is identical to the users primary email or one of his aliases.')
                        });
                        return false;
                    } else {
                        Tine.widgets.grid.QuickaddGridPanel.prototype.onNewentry.call(this, value);
                    }
                },
                cm: new Ext.grid.ColumnModel([{
                    id: 'email', 
                    header: this.app.i18n.gettext('Email Forward'),
                    dataIndex: 'email', 
                    width: 300, 
                    hideable: false, 
                    sortable: true,
                    quickaddField: new Ext.form.TextField({
                        emptyText: this.app.i18n.gettext('Add a forward address...'),
                        vtype: 'email'
                    }),
                    editor: new Ext.form.TextField({allowBlank: false}) 
                }])
            }, commonConfig)
        );
        this.forwardsGrid.render(document.body);
        
        return [
            [this.aliasesGrid, this.forwardsGrid],
            [{hidden: true},
             {
                fieldLabel: this.app.i18n.gettext('Forward Only'),
                name: 'emailForwardOnly',
                xtype: 'checkbox',
                readOnly: false
            }]
        ];
    },
    
    /**
     * @private
     */
    getFormItems: function () {
        this.displayFieldStyle = {
            border: 'silver 1px solid',
            padding: '3px',
            height: '11px'
        };
        
        this.passwordConfirmWindow = new Ext.Window({
            title: this.app.i18n.gettext('Password confirmation'),
            closeAction: 'hide',
            modal: true,
            width: 300,
            height: 150,
            items: [{
                xtype: 'form',
                bodyStyle: 'padding: 5px;',
                buttonAlign: 'right',
                labelAlign: 'top',
                anchor: '100%',
                monitorValid: true,
                defaults: { anchor: '100%' },
                items: [{
                    xtype: 'textfield',
                    inputType: 'password',
                    id: 'passwordRepeat',
                    fieldLabel: this.app.i18n.gettext('Repeat password'),
                    name: 'passwordRepeat',
                    validator: this.onPasswordConfirm.createDelegate(this),
                    listeners: {
                        scope: this,
                        specialkey: function (field, event) {
                            if (event.getKey() === event.ENTER) {
                                // call OK button handler
                                this.passwordConfirmWindow.items.first().buttons[1].handler.call(this);
                            }
                        }
                    }
                }, {
                    xtype: 'displayfield',
                    hideLabel: true,
                    id: 'passwordStatus',
                    value: this.app.i18n.gettext('Passwords do not match!')
                }],
                buttons: [{
                    text: i18n._('Cancel'),
                    iconCls: 'action_cancel',
                    scope: this,
                    handler: function () {
                        this.passwordConfirmWindow.hide();
                    }
                }, {
                    text: i18n._('Ok'),
                    formBind: true,
                    iconCls: 'action_saveAndClose',
                    scope: this,
                    handler: function () {
                        var confirmForm = this.passwordConfirmWindow.items.first().getForm();
                        
                        // check if confirm form is valid (we need this if special key called button handler)
                        if (confirmForm.isValid()) {
                            this.passwordConfirmWindow.hide();
                            // focus email field
                            this.getForm().findField('accountEmailAddress').focus(true, 100);
                        }
                    }
                }]
            }],
            listeners: {
                scope: this,
                show: function (win) {
                    var confirmForm = this.passwordConfirmWindow.items.first().getForm();
                    
                    confirmForm.reset();
                    confirmForm.findField('passwordRepeat').focus(true, 500);
                }
            }
        });
        this.passwordConfirmWindow.render(document.body);
        
        var config = {
            xtype: 'tabpanel',
            deferredRender: false,
            border: false,
            plain: true,
            activeTab: 0,
            items: [{
                title: this.app.i18n.gettext('Account'),
                autoScroll: true,
                border: false,
                frame: true,
                layout: 'hfit',
                items: [{
                    xtype: 'columnform',
                    labelAlign: 'top',
                    formDefaults: {
                        xtype: 'textfield',
                        anchor: '100%',
                        labelSeparator: '',
                        columnWidth: 0.333
                    },
                    items: [[{
                        fieldLabel: this.app.i18n.gettext('First name'),
                        name: 'accountFirstName',
                        columnWidth: 0.5,
                        tabIndex: 1,
                        listeners: {
                            render: function (field) {
                                field.focus(false, 250);
                                field.selectText();
                            }
                        }
                    }, {
                        fieldLabel: this.app.i18n.gettext('Last name'),
                        name: 'accountLastName',
                        allowBlank: false,
                        tabIndex: 2,
                        columnWidth: 0.5
                    }], [{
                        fieldLabel: this.app.i18n.gettext('Login name'),
                        name: 'accountLoginName',
                        allowBlank: false,
                        tabIndex: 3,
                        columnWidth: 0.5
                    }, {
                        fieldLabel: this.app.i18n.gettext('Password'),
                        id: 'accountPassword',
                        name: 'accountPassword',
                        inputType: 'password',
                        columnWidth: 0.5,
                        tabIndex: 4,
                        passwordsMatch: true,
                        enableKeyEvents: true,
                        listeners: {
                            scope: this,
                            blur: function (field) {
                                var fieldValue = field.getValue();
                                if (fieldValue !== '') {
                                    // show password confirmation
                                    // NOTE: we can't use Ext.Msg.prompt because field has to be of inputType: 'password'
                                    this.passwordConfirmWindow.show.defer(100, this.passwordConfirmWindow);
                                }
                            },
                            destroy: function () {
                                // destroy password confirm window
                                this.passwordConfirmWindow.destroy();
                            },
                            keydown: function (field) {
                                field.passwordsMatch = false;
                            }
                        },
                        validateValue: function (value) {
                            return this.passwordsMatch;
                        }
                    }], [{
                        vtype: 'email',
                        fieldLabel: this.app.i18n.gettext('Email'),
                        tabIndex: 5,
                        name: 'accountEmailAddress',
                        id: 'accountEmailAddress',
                        columnWidth: 0.5
                    }, {
                        //vtype: 'email',
                        fieldLabel: this.app.i18n.gettext('OpenID'),
                        emptyText: '(' + this.app.i18n.gettext('Login name') + ')',
                        tabIndex: 6,
                        name: 'openid',
                        columnWidth: 0.5
                    }], [{
                        xtype: 'tinerecordpickercombobox',
                        fieldLabel: this.app.i18n.gettext('Primary group'),
                        tabIndex: 7,
                        listWidth: 250,
                        name: 'accountPrimaryGroup',
                        blurOnSelect: true,
                        allowBlank: false,
                        recordClass: Tine.Admin.Model.Group,
                        listeners: {
                            scope: this,
                            'select': function (combo, record, index) {
                                // refresh grid
                                if (this.pickerGridGroups) {
                                    this.pickerGridGroups.getView().refresh();
                                }
                            }
                        }
                    }, {
                        xtype: 'combo',
                        fieldLabel: this.app.i18n.gettext('Status'),
                        name: 'accountStatus',
                        mode: 'local',
                        triggerAction: 'all',
                        allowBlank: false,
                        tabIndex: 8,
                        editable: false,
                        store: [
                            ['enabled',  this.app.i18n.gettext('enabled')],
                            ['disabled', this.app.i18n.gettext('disabled')],
                            ['expired',  this.app.i18n.gettext('expired')],
                            ['blocked',  this.app.i18n.gettext('blocked')]
                        ],
                        listeners: {
                            scope: this,
                            select: function (combo, record) {
                                switch (record.data.field1) {
                                    case 'blocked':
                                        Ext.Msg.alert(this.app.i18n._('Invalid Status'),
                                            this.app.i18n._('Blocked status is only valid if the user tried to login with a wrong password to often. It is not possible to set this status here.'));
                                        combo.setValue(combo.startValue);
                                        break;
                                    case 'expired':
                                        this.getForm().findField('accountExpires').setValue(new Date());
                                        break;
                                    case 'enabled':
                                        var expiryDateField = this.getForm().findField('accountExpires'),
                                            expiryDate = expiryDateField.getValue(),
                                            now = new Date();
                                            
                                        if (expiryDate < now) {
                                            expiryDateField.setValue('');
                                        }
                                        break;
                                    default:
                                        // do nothing
                                }
                            }
                        }
                    }, {
                        xtype: 'extuxclearabledatefield',
                        fieldLabel: this.app.i18n.gettext('Expires'),
                        name: 'accountExpires',
                        tabIndex: 9,
                        emptyText: this.app.i18n.gettext('never')
                    }], [{
                        xtype: 'combo',
                        fieldLabel: this.app.i18n.gettext('Visibility'),
                        name: 'visibility',
                        mode: 'local',
                        tabIndex: 10,
                        triggerAction: 'all',
                        allowBlank: false,
                        editable: false,
                        store: [['displayed', this.app.i18n.gettext('Display in addressbook')], ['hidden', this.app.i18n.gettext('Hide from addressbook')]],
                        listeners: {
                            scope: this,
                            select: function (combo, record) {
                                // disable container_id combo if hidden
                                var addressbookContainerCombo = this.getForm().findField('container_id');
                                addressbookContainerCombo.setDisabled(record.data.field1 === 'hidden');
                                if (addressbookContainerCombo.getValue() === '') {
                                    addressbookContainerCombo.setValue(null);
                                }
                            }
                        }
                    }, {
                        xtype: 'tinerecordpickercombobox',
                        fieldLabel: this.app.i18n.gettext('Saved in Addressbook'),
                        name: 'container_id',
                        blurOnSelect: true,
                        tabIndex: 11,
                        allowBlank: false,
                        forceSelection: true,
                        listWidth: 250,
                        recordClass: Tine.Tinebase.Model.Container,
                        disabled: this.record.get('visibility') === 'hidden',
                        recordProxy: Tine.Admin.sharedAddressbookBackend,
                        listeners: {
                            specialkey: function(combo, e) {
                                if (e.getKey() == e.TAB && ! e.shiftKey) {
                                    // move cursor to first input field (skip display fields)
                                    // @see 0008226: when tabbing in user edit dialog, wrong tab content is displayed
                                    e.preventDefault();
                                    e.stopEvent();
                                    this.getForm().findField('accountFirstName').focus();
                                }
                            },
                            scope: this
                        }
                    }]] 
                }, {
                    xtype: 'fieldset',
                    title: this.app.i18n.gettext('Information'),
                    autoHeight: true,
                    checkboxToggle: false,
                    layout: 'hfit',
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        formDefaults: {
                            xtype: 'displayfield',
                            anchor: '100%',
                            labelSeparator: '',
                            columnWidth: 0.333,
                            style: this.displayFieldStyle
                        },
                        items: [[{
                            fieldLabel: this.app.i18n.gettext('Last login at'),
                            name: 'accountLastLogin',
                            emptyText: this.ldapBackend ? this.app.i18n.gettext("don't know") : this.app.i18n.gettext('never logged in')
                        }, {
                            fieldLabel: this.app.i18n.gettext('Last login from'),
                            name: 'accountLastLoginfrom',
                            emptyText: this.ldapBackend ? this.app.i18n.gettext("don't know") : this.app.i18n.gettext('never logged in')
                        }, {
                            fieldLabel: this.app.i18n.gettext('Password set'),
                            name: 'accountLastPasswordChange',
                            emptyText: this.app.i18n.gettext('never')
                        }]]
                    }]
                }]
            }, {
                title: this.app.i18n.gettext('User groups'),
                border: false,
                frame: true,
                layout: 'fit',
                items: this.initUserGroups()
            }, {
                title: this.app.i18n.gettext('User roles'),
                border: false,
                frame: true,
                layout: 'fit',
                items: this.initUserRoles()
            }, {
                title: this.app.i18n.gettext('Fileserver'),
                disabled: !this.ldapBackend,
                border: false,
                frame: true,
                items: this.initFileserver()
            }, {
                title: this.app.i18n.gettext('Filesystem'),
                border: false,
                frame: true,
                items: this.initFilesystem()
            }, {
                title: this.app.i18n.gettext('IMAP'),
                disabled: ! Tine.Admin.registry.get('manageImapEmailUser'),
                autoScroll: true,
                border: false,
                frame: true,
                layout: 'hfit',
                items: this.initImap()
            }, {
                xtype: 'columnform',
                title: this.app.i18n.gettext('SMTP'),
                disabled: ! Tine.Admin.registry.get('manageSmtpEmailUser'),
                border: false,
                frame: true,
                labelAlign: 'top',
                formDefaults: {
                    xtype: 'textfield',
                    anchor: '100%',
                    labelSeparator: '',
                    columnWidth: 0.5,
                    readOnly: true
                },
                items: this.initSmtp()
            }]
        };
        return config;
    },

    /**
     * @param value
     * @return boolean
     */
    validateLoginName: function (value) {
        return value.match(/^[a-z\d._-]+$/i) !== null;
    }
});

/**
 * User Edit Popup
 * 
 * @param   {Object} config
 * @return  {Ext.ux.Window}
 */
Tine.Admin.UserEditDialog.openWindow = function (config) {
    var id = (config.record && config.record.id) ? config.record.id : 0;
    var window = Tine.WindowFactory.getWindow({
        width: 600,
        height: 400,
        name: Tine.Admin.UserEditDialog.prototype.windowNamePrefix + id,
        contentPanelConstructor: 'Tine.Admin.UserEditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 308:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @package     Admin
 * @subpackage  User
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         refactor this (don't use Ext.getCmp, extend generic grid panel, ...)
 */

/*global Ext, Tine, Locale*/

Ext.ns('Tine.Admin.Groups');

/*********************************** MAIN DIALOG ********************************************/

Tine.Admin.Groups.Main = {
        
    // references to crated toolbar and grid panel
    groupsToolbar: null,
    gridPanel: null,
        
    actions: {
        addGroup: null,
        editGroup: null,
        deleteGroup: null
    },
    
    handlers: {
        /**
         * onclick handler for addBtn
         */
        addGroup: function (button, event) {
            this.openEditWindow(null);
        },

        /**
         * onclick handler for editBtn
         */
        editGroup: function (button, event) {
            var selectedRows = this.gridPanel.getSelectionModel().getSelections();
            this.openEditWindow(selectedRows[0]);
        },

        
        /**
         * onclick handler for deleteBtn
         */
        deleteGroup: function (button, event) {
            Ext.MessageBox.confirm(this.translation.gettext('Confirm'), this.translation.gettext('Do you really want to delete the selected groups?'), function (button) {
                if (button === 'yes') {
                
                    var groupIds = [],
                        selectedRows = this.gridPanel.getSelectionModel().getSelections();
                        
                    for (var i = 0; i < selectedRows.length; ++i) {
                        groupIds.push(selectedRows[i].id);
                    }
                    
                    Ext.Ajax.request({
                        url: 'index.php',
                        params: {
                            method: 'Admin.deleteGroups',
                            groupIds: groupIds
                        },
                        scope: this,
                        text: this.translation.gettext('Deleting group(s)...'),
                        success: function (result, request) {
                            this.gridPanel.getStore().reload();
                        },
                        failure: function (result, request) {
                            Ext.MessageBox.alert(this.translation.gettext('Failed'), this.translation.gettext('Some error occurred while trying to delete the group.'));
                        }
                    });
                }
            }, this);
        }    
    },
    
    /**
     * open edit window
     * 
     * @param {} record
     */
    openEditWindow: function (record) {
        var popupWindow = Tine.Admin.Groups.EditDialog.openWindow({
            group: record,
            listeners: {
                scope: this,
                'update': function (record) {
                    this.reload();
                }
            }                
        });
    },
    
    initComponent: function () {
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');
        
        this.pageSize = Tine.Tinebase.registry.get('preferences').get('pageSize')
            ? parseInt(Tine.Tinebase.registry.get('preferences').get('pageSize'), 10)
            : 50;
        
        this.actions.addGroup = new Ext.Action({
            text: this.translation.gettext('Add Group'),
            disabled: true,
            handler: this.handlers.addGroup,
            iconCls: 'action_addGroup',
            scope: this
        });
        
        this.actions.editGroup = new Ext.Action({
            text: this.translation.gettext('Edit Group'),
            disabled: true,
            handler: this.handlers.editGroup,
            iconCls: 'action_edit',
            scope: this
        });
        
        this.actions.deleteGroup = new Ext.Action({
            text: this.translation.gettext('Delete Group'),
            disabled: true,
            handler: this.handlers.deleteGroup,
            iconCls: 'action_delete',
            scope: this
        });

    },
    
    displayGroupsToolbar: function () {
        var app = Tine.Tinebase.appMgr.get('Admin');

        // if toolbar was allready created set active toolbar and return
        if (this.groupsToolbar) {
            app.getMainScreen().setActiveToolbar(this.groupsToolbar, true);
            return;
        }
        
        var GroupsAdminQuickSearchField = new Ext.ux.SearchField({
            id: 'GroupsAdminQuickSearchField',
            width: 240,
            emptyText: i18n._hidden('enter searchfilter')
        });
        GroupsAdminQuickSearchField.on('change', function () {
            this.gridPanel.getStore().load({
                params: {
                    start: 0,
                    limit: this.pageSize
                }
            });
        }, this);
        
        this.groupsToolbar = new Ext.Toolbar({
            canonicalName: ['Group', 'ActionToolbar'].join(Tine.Tinebase.CanonicalPath.separator),
            split: false,
            items: [{
                xtype: 'buttongroup',
                columns: 5,
                items: [
                    Ext.apply(new Ext.Button(this.actions.addGroup), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),
                    Ext.apply(new Ext.Button(this.actions.editGroup), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),
                    Ext.apply(new Ext.Button(this.actions.deleteGroup), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    })
                ]
            }, '->', 
                this.translation.gettext('Search:'), 
                ' ',
                GroupsAdminQuickSearchField
            ]
        });

        app.getMainScreen().setActiveToolbar(this.groupsToolbar, true);
    },

    displayGroupsGrid: function () {
        var app = Tine.Tinebase.appMgr.get('Admin');

        // if grid panel was allready created set active content panel and return
        if (this.gridPanel)    {
            app.getMainScreen().setActiveContentPanel(this.gridPanel, true);
            return;
        }
        
        if (Tine.Tinebase.common.hasRight('manage', 'Admin', 'accounts')) {
            this.actions.addGroup.setDisabled(false);
        }

        // the datastore
        var dataStore = new Ext.data.JsonStore({
            baseParams: {
                method: 'Admin.getGroups'
            },
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Admin.Model.Group,
            // turn on remote sorting
            remoteSort: true
        });
        
        dataStore.setDefaultSort('id', 'asc');

        dataStore.on('beforeload', function (dataStore, options) {
            options = options || {};
            options.params = options.params || {};
            options.params.filter = Ext.getCmp('GroupsAdminQuickSearchField').getValue();
        }, this);
        
        // the paging toolbar
        var pagingToolbar = new Ext.PagingToolbar({
            pageSize: this.pageSize,
            store: dataStore,
            displayInfo: true,
            displayMsg: this.translation.gettext('Displaying groups {0} - {1} of {2}'),
            emptyMsg: this.translation.gettext("No groups to display")
        });
        
        // the columnmodel
        var columnModel = new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: [
                { id: 'id', header: this.translation.gettext('ID'), dataIndex: 'id', width: 50, hidden: true },
                { id: 'name', header: this.translation.gettext('Name'), dataIndex: 'name', width: 50 },
                { id: 'description', header: this.translation.gettext('Description'), dataIndex: 'description' },
                { id: 'creation_time',      header: i18n._('Creation Time'),         dataIndex: 'creation_time',         renderer: Tine.Tinebase.common.dateRenderer,        hidden: true, sortable: true },
                { id: 'created_by',         header: i18n._('Created By'),            dataIndex: 'created_by',            renderer: Tine.Tinebase.common.usernameRenderer,    hidden: true, sortable: true },
                { id: 'last_modified_time', header: i18n._('Last Modified Time'),    dataIndex: 'last_modified_time',    renderer: Tine.Tinebase.common.dateRenderer,        hidden: true, sortable: true },
                { id: 'last_modified_by',   header: i18n._('Last Modified By'),      dataIndex: 'last_modified_by',      renderer: Tine.Tinebase.common.usernameRenderer,    hidden: true, sortable: true }
            ]
        });
        
        // the rowselection model
        var rowSelectionModel = new Ext.grid.RowSelectionModel({multiSelect: true});

        rowSelectionModel.on('selectionchange', function (selectionModel) {
            var rowCount = selectionModel.getCount();

            if (Tine.Tinebase.common.hasRight('manage', 'Admin', 'accounts')) {
                if (rowCount < 1) {
                    // no row selected
                    this.actions.deleteGroup.setDisabled(true);
                    this.actions.editGroup.setDisabled(true);
                } else if (rowCount > 1) {
                    // more than one row selected
                    this.actions.deleteGroup.setDisabled(false);
                    this.actions.editGroup.setDisabled(true);
                } else {
                    // only one row selected
                    this.actions.deleteGroup.setDisabled(false);
                    this.actions.editGroup.setDisabled(false);
                }
            }
        }, this);
        
        // the gridpanel
        this.gridPanel = new Ext.grid.GridPanel({
            canonicalName: ['Group', 'Grid'].join(Tine.Tinebase.CanonicalPath.separator),
            store: dataStore,
            cm: columnModel,
            tbar: pagingToolbar,     
            autoSizeColumns: false,
            selModel: rowSelectionModel,
            enableColLock: false,
            autoExpandColumn: 'n_family',
            border: false,
            view: new Ext.grid.GridView({
                autoFill: true,
                forceFit: true,
                ignoreAdd: true,
                emptyText: this.translation.gettext('No groups to display')
            }),
            enableHdMenu: false,
            plugins: [new Ext.ux.grid.GridViewMenuPlugin()]
        });

        this.gridPanel.on('rowcontextmenu', function (grid, rowIndex, eventObject) {
            eventObject.stopEvent();
            if (! grid.getSelectionModel().isSelected(rowIndex)) {
                grid.getSelectionModel().selectRow(rowIndex);
            }
            
            if (! this.contextMenu) {
                this.contextMenu = new Ext.menu.Menu({
                    id: 'ctxMenuGroups',
                    plugins: [{
                        ptype: 'ux.itemregistry',
                        key:   'Tinebase-MainContextMenu'
                    }],
                    items: [
                        this.actions.editGroup,
                        this.actions.deleteGroup,
                        '-',
                        this.actions.addGroup 
                    ]
                });
            }
            this.contextMenu.showAt(eventObject.getXY());
        }, this);
        
        this.gridPanel.on('rowdblclick', function (gridPar, rowIndexPar, ePar) {
            if (Tine.Tinebase.common.hasRight('manage', 'Admin', 'accounts')) {
                var record = gridPar.getStore().getAt(rowIndexPar);
                this.openEditWindow(record);
            }
        }, this);

        // add the grid to the layout
        app.getMainScreen().setActiveContentPanel(this.gridPanel, true);
    },
    
    /**
     * update datastore with node values and load datastore
     */
    loadData: function () {
        var dataStore = this.gridPanel.getStore();
        dataStore.load({ params: { start: 0, limit: this.pageSize } });
    },

    show: function () {
        if (this.groupsToolbar === null || this.gridPanel === null) {
            this.initComponent();
        }

        this.displayGroupsToolbar();
        this.displayGroupsGrid();

        this.loadData();
    },
    
    reload: function () {
        if (this.gridPanel) {
            this.gridPanel.getStore().reload.defer(200, this.gridPanel.getStore());
        }
    }
};


/***/ }),

/***/ 309:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2007-2012 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         refactor this (use more methods from Tine.widgets.dialog.EditRecord)
 */

/*global Ext, Tine, Locale*/

Ext.ns('Tine.Admin.Groups');

/**
 * @namespace   Tine.Admin.Groups
 * @class       Tine.Admin.Groups.EditDialog
 * @extends     Tine.widgets.dialog.EditRecord
 */
Tine.Admin.Groups.EditDialog = Ext.extend(Tine.widgets.dialog.EditRecord, {
    /**
     * var group
     */
    group: null,

    windowNamePrefix: 'groupEditWindow_',
    
    id: 'groupDialog',
    layout: 'fit',
    border: false,
    labelWidth: 120,
    labelAlign: 'top',
    
    handlerApplyChanges: function(button, event, closeWindow) {
        var form = this.getForm();
        
        if (form.isValid()) {
            Ext.MessageBox.wait(this.translation.gettext('Please wait'), this.translation.gettext('Updating Memberships'));
            
            // get group members
            var groupMembers = [];
            this.membersStore.each(function (record) {
                groupMembers.push(record.id);
            });
            
            // update record with form data               
            form.updateRecord(this.group);

            /*********** save group members & form ************/
            
            Ext.Ajax.request({
                params: {
                    method: 'Admin.saveGroup', 
                    groupData: this.group.data,
                    groupMembers: groupMembers
                },
                success: function (response) {
                    /*
                    if(window.opener.Tine.Admin.Groups) {
                        window.opener.Tine.Admin.Groups.Main.reload();
                    }
                    */
                    this.fireEvent('update', Ext.util.JSON.encode(this.group.data));
                    if (closeWindow === true) {
                        //window.close();
                        this.window.close();
                    } else {
                        this.onRecordLoad(response);
                    }
                    Ext.MessageBox.hide();
                },
                failure: function (result, request) {
                    Ext.MessageBox.alert(this.translation.gettext('Failed'), this.translation.gettext('Could not save group.'));
                },
                scope: this 
            });
        } else {
            Ext.MessageBox.alert(this.translation.gettext('Errors'), this.translation.gettext('Please fix the errors noted.'));
        }
    },
    
    /**
     * function updateRecord
     */
    updateRecord: function (groupData) {
        // if groupData is empty (=array), set to empty object because array won't work!
        if (groupData.length === 0) {
            groupData = {};
        }
        this.group = new Tine.Admin.Model.Group(groupData, groupData.id ? groupData.id : 0);
        
        // tweak, as group members are not in standard form cycle yet
        this.membersStore.loadData(this.group.get('groupMembers'));
    },

    /**
     * function updateToolbarButtons
     * 
     */
    updateToolbarButtons: function (rights) {
    },
    
    /**
     * function getFormContents
     * 
     */
    getFormContents: function () {
        var editGroupDialog = {
            layout: 'border',
            border: false,
            width: 600,
            height: 500,
            items: [{
                region: 'north',
                xtype: 'columnform',
                border: false,
                autoHeight: true,
                items: [[{
                    columnWidth: 1,
                    xtype: 'textfield',
                    fieldLabel: this.translation.gettext('Group Name'), 
                    name: 'name',
                    anchor: '100%',
                    allowBlank: false
                }], [{
                    columnWidth: 1,
                    xtype: 'textarea',
                    name: 'description',
                    fieldLabel: this.translation.gettext('Description'),
                    grow: false,
                    preventScrollbars: false,
                    anchor: '100%',
                    height: 60
                }], [{
                    columnWidth: 0.5,
                    xtype: 'combo',
                    fieldLabel: this.translation.gettext('Visibility'),
                    name: 'visibility',
                    mode: 'local',
                    triggerAction: 'all',
                    allowBlank: false,
                    editable: false,
                    store: [['displayed', this.translation.gettext('Display in addressbook')], ['hidden', this.translation.gettext('Hide from addressbook')]],
                    listeners: {
                        scope: this,
                        select: function (combo, record) {
                            // disable container_id combo if hidden
                            this.getForm().findField('container_id').setDisabled(record.data.field1 === 'hidden');
                            if(record.data.field1 === 'hidden') {
                                this.getForm().findField('container_id').clearInvalid();
                            } else {
                                this.getForm().findField('container_id').isValid();
                            }
                        }
                    }
                }, {
                    columnWidth: 0.5,
                    xtype: 'tinerecordpickercombobox',
                    fieldLabel: this.translation.gettext('Saved in Addressbook'),
                    name: 'container_id',
                    blurOnSelect: true,
                    allowBlank: false,
                    listWidth: 250,
                    recordClass: Tine.Tinebase.Model.Container,
                    recordProxy: Tine.Admin.sharedAddressbookBackend,
                    disabled: this.group.get('visibility') === 'hidden'
                }]]
            }, {
                xtype: 'tinerecordpickergrid',
                title: this.translation.gettext('Group Members'),
                store: this.membersStore,
                region: 'center',
                anchor: '100% 100%',
                showHidden: true
            }]
        };
        
        return editGroupDialog;
    },
    
    initComponent: function () {
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');
        
        this.group = this.group ? this.group : new Tine.Admin.Model.Group({}, 0);
        
        if (this.group.id !== 0) {
            Ext.Ajax.request({
                scope: this,
                success: this.onRecordLoad,
                params: {
                    method: 'Admin.getGroup',
                    groupId: this.group.id
                }
            });
        } else {
            this.group = new Tine.Admin.Model.Group(Tine.Admin.Model.Group.getDefaultData(), 0);
        }
                
        this.membersStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Tinebase.Model.Account
        });
        
        this.items = this.getFormContents();
        Tine.Admin.Groups.EditDialog.superclass.initComponent.call(this);
    },
    
    onRender: function (ct, position) {
        Tine.widgets.dialog.EditDialog.superclass.onRender.call(this, ct, position);
        
        // generalized keybord map for edit dlgs
        var map = new Ext.KeyMap(this.el, [{
            key: [10, 13], // ctrl + return
            ctrl: true,
            fn: this.handlerApplyChanges.createDelegate(this, [true], true),
            scope: this
        }]);

        this.loadMask = new Ext.LoadMask(ct, {msg: String.format(i18n._('Transferring {0}...'), this.translation.gettext('Group'))});
        
        if (this.group.id !== 0) {
            this.loadMask.show();
        } else {
            this.window.setTitle(this.translation.gettext('Add new group'));
            this.getForm().loadRecord(this.group);
        }
    },
    
    onRecordLoad: function (response) {
        this.getForm().findField('name').focus(false, 350);
        var recordData = Ext.util.JSON.decode(response.responseText);
        this.updateRecord(recordData);

        if (! this.group.id) {
            this.window.setTitle(this.translation.gettext('Add new group'));
        } else {
            this.window.setTitle(String.format(this.translation.gettext('Edit Group "{0}"'), this.group.get('name')));
        }

        this.getForm().loadRecord(this.group);
        this.updateToolbarButtons();
        
        this.loadMask.hide();
    }
});


/**
 * Groups Edit Popup
 */
Tine.Admin.Groups.EditDialog.openWindow = function (config) {
    config.group = config.group ? config.group : new Tine.Admin.Model.Group({}, 0);
    var window = Tine.WindowFactory.getWindow({
        width: 400,
        height: 600,
        name: Tine.Admin.Groups.EditDialog.prototype.windowNamePrefix + config.group.id,
        contentPanelConstructor: 'Tine.Admin.Groups.EditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 310:
/***/ (function(module, exports) {

/**
 * Tine 2.0
 * 
 * @package     Admin
 * @subpackage  AccessLog
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philip Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2010-2014 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.ns('Tine.Admin.accessLog');

/**
 * AccessLog 'mainScreen'
 * 
 * @static
 */
Tine.Admin.accessLog.show = function () {
    var app = Tine.Tinebase.appMgr.get('Admin');
    if (! Tine.Admin.accessLog.gridPanel) {
        Tine.Admin.accessLog.gridPanel = new Tine.Admin.accessLog.GridPanel({
            app: app
        });
    }
    else {
        Tine.Admin.accessLog.gridPanel.loadGridData.defer(100, Tine.Admin.accessLog.gridPanel, []);
    }

    app.getMainScreen().setActiveContentPanel(Tine.Admin.accessLog.gridPanel, true);
    app.getMainScreen().setActiveToolbar(Tine.Admin.accessLog.gridPanel.actionToolbar, true);
};

/**
 * AccessLog grid panel
 * 
 * @namespace   Tine.Admin.accessLog
 * @class       Tine.Admin.accessLog.GridPanel
 * @extends     Tine.widgets.grid.GridPanel
 */
Tine.Admin.accessLog.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    
    recordClass: Tine.Admin.Model.AccessLog,
    recordProxy: Tine.Admin.accessLogBackend,
    defaultSortInfo: {field: 'li', direction: 'DESC'},
    evalGrants: false,
    gridConfig: {
        id: 'gridAdminAccessLogs',
        autoExpandColumn: 'login_name'
    },
    
    initComponent: function() {
        this.gridConfig.columns = this.getColumns();
        Tine.Admin.accessLog.GridPanel.superclass.initComponent.call(this);
    },
    
    /**
     * init actions with actionToolbar, contextMenu and actionUpdater
     * 
     * @private
     */
    initActions: function() {
        
        this.initDeleteAction();
        
        this.actionUpdater.addActions([
            this.action_deleteRecord
        ]);
        
        this.actionToolbar = new Ext.Toolbar({
            items: [{
                xtype: 'buttongroup',
                columns: 1,
                items: [
                    Ext.apply(new Ext.Button(this.action_deleteRecord), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top',
                        arrowAlign:'right'
                    })
                ]}
             ]
        });
        
        if (this.filterToolbar && typeof this.filterToolbar.getQuickFilterField == 'function') {
            this.actionToolbar.add('->', this.filterToolbar.getQuickFilterField());
        }
        
        this.contextMenu = new Ext.menu.Menu({
            items: [this.action_deleteRecord],
            plugins: [{
                ptype: 'ux.itemregistry',
                key:   'Tinebase-MainContextMenu'
            }]
        });
    },
    
    /**
     * initialises filter toolbar
     */
    initFilterPanel: function() {
        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
            filterModels: [
                {label: this.app.i18n._('Access Log'),  field: 'query',         operators: ['contains']},
                {label: this.app.i18n._('IP Address'),  field: 'ip'},
                {label: this.app.i18n._('User'),        field: 'account_id',    valueType: 'user'},
                {label: this.app.i18n._('Login Time'),  field: 'li',            valueType: 'date', pastOnly: true        },
                {label: this.app.i18n._('Logout Time'), field: 'lo',            valueType: 'date', pastOnly: true        },
                {label: this.app.i18n._('Client Type'), field: 'clienttype'}
            ],
            defaultFilter: 'query',
            filters: [
                {field: 'li',           operator: 'within', value: 'weekThis'}
                //{field: 'clienttype',   operator: 'equals', value: 'JSON-RPC'}
            ],
            plugins: [
                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
            ]
        });
        this.plugins = this.plugins || [];
        this.plugins.push(this.filterToolbar);
    },
    
    /**
     * returns cm
     * @private
     */
    getColumns: function(){
        return [
            { header: this.app.i18n._('Session ID'), id: 'sessionid', dataIndex: 'sessionid', width: 200, hidden: true},
            { header: this.app.i18n._('Login Name'), id: 'login_name', dataIndex: 'login_name'},
            { header: this.app.i18n._('Name'), id: 'account_id', dataIndex: 'account_id', width: 170, sortable: false, renderer: Tine.Tinebase.common.usernameRenderer},
            { header: this.app.i18n._('IP Address'), id: 'ip', dataIndex: 'ip', width: 150},
            { header: this.app.i18n._('Login Time'), id: 'li', dataIndex: 'li', width: 140, renderer: Tine.Tinebase.common.dateTimeRenderer},
            { header: this.app.i18n._('Logout Time'), id: 'lo', dataIndex: 'lo', width: 140, renderer: Tine.Tinebase.common.dateTimeRenderer},
            { header: this.app.i18n._('Result'), id: 'result', dataIndex: 'result', width: 110, renderer: this.resultRenderer, scope: this},
            { header: this.app.i18n._('Client Type'), id: 'clienttype', dataIndex: 'clienttype', width: 50}
        ];
    },
    
    /**
     * result renderer
     * 
     * @param {} _value
     * @param {} _cellObject
     * @param {} _record
     * @param {} _rowIndex
     * @param {} _colIndex
     * @param {} _dataStore
     * @return String
     */
    resultRenderer: function(_value, _cellObject, _record, _rowIndex, _colIndex, _dataStore) {
        var gridValue;
        
        switch (_value) {
            case '-102' :
                gridValue = this.app.i18n._('user blocked');
                break;

            case '-101' :
                gridValue = this.app.i18n._('password expired');
                break;

            case '-100' :
                gridValue = this.app.i18n._('user disabled');
                break;

            case '-3' :
                gridValue = this.app.i18n._('invalid password');
                break;

            case '-2' :
                gridValue = this.app.i18n._('ambiguous username');
                break;

            case '-1' :
                gridValue = this.app.i18n._('user not found');
                break;

            case '0' :
                gridValue = this.app.i18n._('failure');
                break;

            case '1' :
                gridValue = this.app.i18n._('success');
                break;
        }
        
        return gridValue;
    }
});


/***/ }),

/***/ 311:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @package     Admin
 * @subpackage  sambaMachine
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.ns('Tine.Admin.Model');

Tine.Admin.Model.sambaMachineArray = [
    { name: 'accountId'            },
    { name: 'accountLoginName'     },
    { name: 'accountLastName'      },
    { name: 'accountFullName'      },
    { name: 'accountDisplayName'   },
    { name: 'accountPrimaryGroup'  },
    { name: 'accountHomeDirectory' },
    { name: 'accountLoginShell'    },
    { name: 'sid'                  },
    { name: 'primaryGroupSID'      },
    { name: 'acctFlags'            },
    //{ name: 'logonTime',     type: 'date', dateFormat: Date.patterns.ISO8601Long },
    //{ name: 'logoffTime',    type: 'date', dateFormat: Date.patterns.ISO8601Long },
    //{ name: 'kickoffTime',   type: 'date', dateFormat: Date.patterns.ISO8601Long },
    //{ name: 'pwdLastSet',    type: 'date', dateFormat: Date.patterns.ISO8601Long },
    //{ name: 'pwdCanChange',  type: 'date', dateFormat: Date.patterns.ISO8601Long },
    { name: 'pwdMustChange', type: 'date', dateFormat: Date.patterns.ISO8601Long }
];

Tine.Admin.Model.SambaMachine = Tine.Tinebase.data.Record.create(Tine.Admin.Model.sambaMachineArray, {
    appName: 'Admin',
    modelName: 'SambaMachine',
    idProperty: 'accountId',
    titleProperty: 'accountDisplayName',
    // ngettext('Computer', 'Computers', n);
    recordName: 'Computer',
    recordsName: 'Computers'
});

Tine.Admin.sambaMachineBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'SambaMachine',
    recordClass: Tine.Admin.Model.SambaMachine,
    idProperty: 'accountId'
});


/***/ }),

/***/ 312:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2009-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Admin.sambaMachine');

/**
 * Samba machine 'mainScreen'
 */
Tine.Admin.sambaMachine.show = function() {
    var app = Tine.Tinebase.appMgr.get('Admin');
    if (! Tine.Admin.sambaMachine.gridPanel) {
        Tine.Admin.sambaMachine.gridPanel = new Tine.Admin.SambaMachineGridPanel({
            app: app
        });
    } else {
        setTimeout ("Ext.getCmp('gridAdminComputers').getStore().load({ params: { start:0, limit:50 } })", 100);
    }
    
    Tine.Tinebase.MainScreen.setActiveContentPanel(Tine.Admin.sambaMachine.gridPanel, true);
    Tine.Tinebase.MainScreen.setActiveToolbar(Tine.Admin.sambaMachine.gridPanel.actionToolbar, true);
};

/**
 * SambaMachine grid panel
 *
 * @namespace   Tine.Admin.sambaMachine
 * @class       Tine.Admin.SambaMachineGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 */
Tine.Admin.SambaMachineGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    // model generics
    recordClass: Tine.Admin.Model.SambaMachine,
    recordProxy: Tine.Admin.sambaMachineBackend,
    defaultSortInfo: {field: 'accountLoginName', direction: 'ASC'},
    evalGrants: false,
    gridConfig: {
        id: 'gridAdminComputers',
        autoExpandColumn: 'accountDisplayName'
    },
    
    initComponent: function() {
        this.gridConfig.columns = this.getColumns();
        Tine.Admin.SambaMachineGridPanel.superclass.initComponent.call(this);
    },
    
    /**
     * initialises filter toolbar
     */
    initFilterPanel: function() {
        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
            filterModels: [
                {label: this.app.i18n._('Computer Name'),    field: 'query',       operators: ['contains']}
                //{label: this.app.i18n._('Description'),    field: 'description', operators: ['contains']},
            ],
            defaultFilter: 'query',
            filters: [],
            plugins: [
                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
            ]
        });
        this.plugins = this.plugins || [];
        this.plugins.push(this.filterToolbar);
    },
    
    /**
     * returns cm
     * @private
     */
    getColumns: function(){
        return [{
            id: 'accountId',
            header: this.app.i18n._("ID"),
            width: 100,
            sortable: true,
            dataIndex: 'accountId',
            hidden: true
        },{
            id: 'accountLoginName',
            header: this.app.i18n._("Name"),
            width: 350,
            sortable: true,
            dataIndex: 'accountLoginName'
        },{
            id: 'accountDisplayName',
            header: this.app.i18n._("Description"),
            width: 350,
            sortable: true,
            dataIndex: 'accountDisplayName'
        }];
    }
});


/***/ }),

/***/ 313:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @package     Admin
 * @subpackage  SambaMachine
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.ns('Tine.Admin.sambaMachine');

/**
 * @namespace   Tine.Admin.sambaMachine
 * @class       Tine.Admin.SambaMachineEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 */
Tine.Admin.SambaMachineEditDialog  = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    windowNamePrefix: 'sambaMachineEditWindow_',
    appName: 'Admin',
    recordClass: Tine.Admin.Model.SambaMachine,
    recordProxy: Tine.Admin.sambaMachineBackend,
    evalGrants: false,
    
    getFormItems: function() {
        return {
            xtype: 'columnform',
            labelAlign: 'top',
            border: false,
            formDefaults: {
                xtype:'textfield',
                anchor: '100%',
                labelSeparator: '',
                columnWidth: 1
            },
            items: [[{
                fieldLabel: this.app.i18n._('Computer Name'),
                name: 'accountLoginName'
            }]]
        };
    }
});

/**
 * User edit popup
 */
Tine.Admin.SambaMachineEditDialog.openWindow = function (config) {
    var id = (config.record && config.record.id) ? config.record.id : 0;
    var window = Tine.WindowFactory.getWindow({
        width: 300,
        height: 100,
        name: Tine.Admin.SambaMachineEditDialog.windowNamePrefix + id,
        contentPanelConstructor: 'Tine.Admin.SambaMachineEditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 314:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         split into two files (grid & edit dlg)
 * TODO         fix autoheight in edit dlg (use border layout?)
 */
 
/*global Ext, Tine, Locale*/

Ext.ns('Tine.Admin.Tags');

Tine.Admin.Tags.Main = {
    
    //  references to created toolbar and grid panel
    tagsToolbar: null,
    gridPanel: null,
    
    actions: {
        addTag: null,
        editTag: null,
        deleteTag: null
    },
    
    handlers: {
        /**
         * onclick handler for addBtn
         */
        addTag: function (button, event) {
            Tine.Admin.Tags.EditDialog.openWindow({
                tag: null,
                listeners: {
                    scope: this,
                    'update': function (record) {
                        this.reload();
                    }
                }
            });
        },

        /**
         * onclick handler for editBtn
         */
        editTag: function (button, event) {
            var selectedRows = this.gridPanel.getSelectionModel().getSelections();
            Tine.Admin.Tags.EditDialog.openWindow({
                tag: selectedRows[0],
                listeners: {
                    scope: this,
                    'update': function (record) {
                        this.reload();
                    }
                }
            });
        },
        
        /**
         * onclick handler for deleteBtn
         */
        deleteTag: function (button, event) {
            Ext.MessageBox.confirm(this.translation.gettext('Confirm'), this.translation.gettext('Do you really want to delete the selected tags?'), function (button) {
                if (button === 'yes') {
                
                    var tagIds = [],
                        selectedRows = this.gridPanel.getSelectionModel().getSelections();
                        
                    for (var i = 0; i < selectedRows.length; ++i) {
                        tagIds.push(selectedRows[i].id);
                    }
                    
                    tagIds = tagIds;
                    
                    Ext.Ajax.request({
                        url: 'index.php',
                        params: {
                            method: 'Admin.deleteTags',
                            tagIds: tagIds
                        },
                        text: this.translation.gettext('Deleting tag(s)...'),
                        success: function (result, request) {
                            this.gridPanel.getStore().reload();
                        },
                        scope: this
                    });
                }
            }, this);
        }    
    },
    
    initComponent: function () {
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');
        
        this.pageSize = Tine.Tinebase.registry.get('preferences').get('pageSize')
            ? parseInt(Tine.Tinebase.registry.get('preferences').get('pageSize'), 10)
            : 50;
        
        this.actions.addTag = new Ext.Action({
            text: this.translation.gettext('Add Tag'),
            handler: this.handlers.addTag,
            iconCls: 'action_tag',
            scope: this,
            disabled: !(Tine.Tinebase.common.hasRight('manage', 'Admin', 'shared_tags'))
        });
        
        this.actions.editTag = new Ext.Action({
            text: this.translation.gettext('Edit Tag'),
            disabled: true,
            handler: this.handlers.editTag,
            iconCls: 'action_edit',
            scope: this
        });
        
        this.actions.deleteTag = new Ext.Action({
            text: this.translation.gettext('Delete Tag'),
            disabled: true,
            handler: this.handlers.deleteTag,
            iconCls: 'action_delete',
            scope: this
        });

    },
    
    displayTagsToolbar: function () {
        // if toolbar was allready created set active toolbar and return
        if (this.tagsToolbar) {
            Tine.Tinebase.MainScreen.setActiveToolbar(this.tagsToolbar, true);
            return;
        }
        
        var TagsQuickSearchField = new Ext.ux.SearchField({
            id: 'TagsQuickSearchField',
            width: 240,
            emptyText: i18n._hidden('enter searchfilter')
        });
        
        TagsQuickSearchField.on('change', function () {
            this.gridPanel.getStore().load({
                params: {
                    start: 0,
                    limit: this.pageSize
                }
            });
        }, this);
        
        this.tagsToolbar = new Ext.Toolbar({
            canonicalName: ['Tag', 'ActionToolbar'].join(Tine.Tinebase.CanonicalPath.separator),
            split: false,
            //height: 26,
            items: [{
                xtype: 'buttongroup',
                columns: 5,
                items: [
                    Ext.apply(new Ext.Button(this.actions.addTag), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),
                    Ext.apply(new Ext.Button(this.actions.editTag), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),
                    Ext.apply(new Ext.Button(this.actions.deleteTag), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    })
                ]
            }, '->', 
                this.translation.gettext('Search:'), 
                ' ',
                TagsQuickSearchField
            ]
        });

        Tine.Tinebase.MainScreen.setActiveToolbar(this.tagsToolbar, true);
    },

    displayTagsGrid: function () {
        // if grid panel was allready created set active content panel and return
        if (this.gridPanel) {
            Tine.Tinebase.MainScreen.setActiveContentPanel(this.gridPanel, true);
            return;
        }
        
        // the datastore
        var dataStore = new Ext.data.JsonStore({
            baseParams: {
                method: 'Admin.getTags'
            },
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Tinebase.Model.Tag,
            // turn on remote sorting
            remoteSort: true
        });
        
        dataStore.setDefaultSort('name', 'asc');

        dataStore.on('beforeload', function (dataStore, options) {
            options = options || {};
            options.params = options.params || {};
            options.params.query = Ext.getCmp('TagsQuickSearchField').getValue();
        }, this);
                
        // the paging toolbar
        var pagingToolbar = new Ext.PagingToolbar({
            pageSize: this.pageSize,
            store: dataStore,
            displayInfo: true,
            displayMsg: this.translation.gettext('Displaying tags {0} - {1} of {2}'),
            emptyMsg: this.translation.gettext("No tags to display")
        });
        
        // the columnmodel
        var columnModel = new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: [
                { id: 'color', header: this.translation.gettext('Color'), dataIndex: 'color', width: 25, renderer: function (color,meta,record) {
                    return '<div style="margin-top:1px;width: 8px; height: 8px; background-color:' + color + '; border-radius:5px;border: 1px solid black;" title="' + record.get('name') + ' (' +  i18n._('Usage:&#160;') + record.get('occurrence') + ')">&#160;</div>';
                }},
                { id: 'name', header: this.translation.gettext('Name'), dataIndex: 'name', width: 200 },
                { id: 'description', header: this.translation.gettext('Description'), dataIndex: 'description', width: 500}
            ]
        });
        
        // the rowselection model
        var rowSelectionModel = new Ext.grid.RowSelectionModel({multiSelect: true});

        rowSelectionModel.on('selectionchange', function (selectionModel) {
            var rowCount = selectionModel.getCount();

            if (Tine.Tinebase.common.hasRight('manage', 'Admin', 'shared_tags')) {
                if (rowCount < 1) {
                    // no row selected
                    this.actions.deleteTag.setDisabled(true);
                    this.actions.editTag.setDisabled(true);
                } else if (rowCount > 1) {
                    // more than one row selected
                    this.actions.deleteTag.setDisabled(false);
                    this.actions.editTag.setDisabled(true);
                } else {
                    // only one row selected
                    this.actions.deleteTag.setDisabled(false);
                    this.actions.editTag.setDisabled(false);
                }
            }
        }, this);
        
        // the gridpanel
        this.gridPanel = new Ext.grid.GridPanel({
            canonicalName: ['Tag', 'Grid'].join(Tine.Tinebase.CanonicalPath.separator),
            store: dataStore,
            cm: columnModel,
            tbar: pagingToolbar,     
            autoSizeColumns: false,
            selModel: rowSelectionModel,
            enableColLock: false,
            autoExpandColumn: 'description',
            border: false,
            view: new Ext.grid.GridView({
                autoFill: true,
                forceFit: true,
                ignoreAdd: true,
                emptyText: this.translation.gettext('No tags to display')
            })            
        });
        
        this.gridPanel.on('rowcontextmenu', function (grid, rowIndex, eventObject) {
            eventObject.stopEvent();
            if (! grid.getSelectionModel().isSelected(rowIndex)) {
                grid.getSelectionModel().selectRow(rowIndex);
            }
            
            if (! this.contextMenu) {
                this.contextMenu = new Ext.menu.Menu({
                    id: 'ctxMenuTags',
                    plugins: [{
                        ptype: 'ux.itemregistry',
                        key:   'Tinebase-MainContextMenu'
                    }],
                    items: [
                        this.actions.editTag,
                        this.actions.deleteTag,
                        '-',
                        this.actions.addTag 
                    ]
                });
            }
            this.contextMenu.showAt(eventObject.getXY());
        }, this);
        
        this.gridPanel.on('rowdblclick', function (gridPar, rowIndexPar, ePar) {
            var record = gridPar.getStore().getAt(rowIndexPar);
            Tine.Admin.Tags.EditDialog.openWindow({
                tag: record,
                listeners: {
                    scope: this,
                    'update': function (record) {
                        this.reload();
                    }
                }
            });
        }, this);

        // add the grid to the layout
        Tine.Tinebase.MainScreen.setActiveContentPanel(this.gridPanel, true);
    },
    
    /**
     * update datastore with node values and load datastore
     */
    loadData: function () {
        var dataStore = this.gridPanel.getStore();
        dataStore.load({ params: { start: 0, limit: this.pageSize } });
    },

    show: function () {
        if (this.tagsToolbar === null || this.gridPanel) {
            this.initComponent();
        }

        this.displayTagsToolbar();
        this.displayTagsGrid();

        this.loadData();
    },

    reload: function () {
        if (this.gridPanel) {
            this.gridPanel.getStore().reload.defer(200, this.gridPanel.getStore());
        }
    }
};


/***/ }),

/***/ 315:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philip Schuele <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         refactor this (don't use Ext.getCmp, etc.)
 */

/*global Ext, Tine, Locale*/

Ext.ns('Tine.Admin.Tags');

/**
 * @namespace   Tine.Admin.Tags
 * @class       Tine.Admin.Tags.EditDialog
 * @extends     Tine.widgets.dialog.EditRecord
 */
Tine.Admin.Tags.EditDialog = Ext.extend(Tine.widgets.dialog.EditRecord, {
    
    /**
     * var tag
     */
    tag: null,

    windowNamePrefix: 'AdminTagEditDialog_',
    id: 'tagDialog',
    layout: 'fit',
    border: false,
    labelWidth: 120,
    labelAlign: 'top',
    
    handlerApplyChanges: function (button, event, closeWindow) {
        var form = this.getForm();
        
        if (form.isValid()) {
            Ext.MessageBox.wait(this.translation.gettext('Please wait'), this.translation.gettext('Updating Tag'));
            
            var tag = this.tag;
            
            // fetch rights
            tag.data.rights = [];
            this.rightsStore.each(function (item) {
                tag.data.rights.push(item.data);
            });
            
            // fetch contexts
            tag.data.contexts = [];
            var anycontext = true;
            var contextPanel = Ext.getCmp('adminSharedTagsContextPanel');
            contextPanel.getRootNode().eachChild(function (node) {
                if (node.attributes.checked) {
                    tag.data.contexts.push(node.id);
                } else {
                    anycontext = false;
                }
            });
            if (anycontext) {
                tag.data.contexts = ['any'];
            }
            
            form.updateRecord(tag);
            
            Ext.Ajax.request({
                params: {
                    method: 'Admin.saveTag', 
                    tagData: tag.data
                },
                success: function (response) {
                    this.fireEvent('update', Ext.util.JSON.encode(this.tag.data));
                    Ext.MessageBox.hide();
                    if (closeWindow === true) {
                        this.window.close();
                    } else {
                        this.onRecordLoad(response);
                    }
                },
                failure: function (result, request) {
                    var responseText = Ext.util.JSON.decode(result.responseText),
                        message = (responseText && responseText.message) ? responseText.message : 'unknown error';
                    
                    Ext.MessageBox.alert(
                        this.translation._('Failed'),
                        String.format(this.translation._('Could not save tag ({0})'), message)
                    );
                },
                scope: this 
            });
        } else {
            Ext.MessageBox.alert(this.translation.gettext('Errors'), this.translation.gettext('Please fix the errors noted.'));
        }
    },

    /**
     * function updateRecord
     */
    updateRecord: function (tagData) {
        // if tagData is empty (=array), set to empty object because array wont work!
        if (tagData.length === 0) {
            tagData = {};
        }
        this.tag = new Tine.Tinebase.Model.Tag(tagData, tagData.id ? tagData.id : 0);
        
        if (! tagData.rights) {
            tagData.rights = Tine.Tinebase.configManager.get('anyoneAccountDisabled') ? [] : [{
                tag_id: '', //todo!
                account_name: 'Anyone',
                account_id: 0,
                account_type: 'anyone',
                view_right: true,
                use_right: true
            }];
        }
        
        this.rightsStore.loadData({
            results:    tagData.rights,
            totalcount: tagData.rights.length
        });
        
        this.anyContext = ! tagData.contexts || tagData.contexts.indexOf('any') > -1;
        this.createTreeNodes(tagData.appList);
        this.getForm().loadRecord(this.tag);
    },

    /**
     * function updateToolbarButtons
     */
    updateToolbarButtons: function (rights) {
       /* if(_rights.editGrant === true) {
            Ext.getCmp('tagDialog').action_saveAndClose.enable();
            Ext.getCmp('tagDialog').action_applyChanges.enable();
        }
       */

    },
    
    createTreeNodes: function (appList) {
        // clear old childs
        var toRemove = [];
        this.rootNode.eachChild(function (node) {
            toRemove.push(node);
        });
        
        for (var i = 0, j = appList.length; i < j; i += 1) {
            // don't duplicate tree nodes on 'apply changes'
            toRemove[i] ? toRemove[i].remove() : null;
            
            var appData = appList[i];
            if (appData.name === 'Tinebase') {
                continue;
            }
            // get translated app title
            var app = Tine.Tinebase.appMgr.get(appData.name),
                appTitle = (app) ? app.getTitle() : appData.name;
            
            this.rootNode.appendChild(new Ext.tree.TreeNode({
                text: appTitle,
                id: appData.id,
                checked: this.anyContext || this.tag.get('contexts').indexOf(appData.id) > -1,
                leaf: true,
                iconCls: 'x-tree-node-leaf-checkbox'
            }));
        }
    },
    /**
     * function display
     */
    getFormContents: function () {

        this.rootNode = new Ext.tree.TreeNode({
            text: this.translation.gettext('Allowed Contexts'),
            expanded: true,
            draggable: false,
            allowDrop: false
        });
        var contextPanel = new Ext.tree.TreePanel({
            title: this.translation.gettext('Context'),
            id: 'adminSharedTagsContextPanel',
            rootVisible: true,
            border: false,
            root: this.rootNode
        });
        // sort nodes in context panel by text property
        var treeSorter = new Ext.tree.TreeSorter(contextPanel, {
            folderSort: true,
            dir: "asc"
        });
        
        this.rightsPanel = new Tine.widgets.account.PickerGridPanel({
            title: this.translation.gettext('Account Rights'),
            store: this.rightsStore,
            recordClass: Tine.Admin.Model.TagRight,
            hasAccountPrefix: true,
            selectType: 'both',
            selectTypeDefault: 'group',
            showHidden: true,
            configColumns: [
                new Ext.ux.grid.CheckColumn({
                    header: this.translation.gettext('View'),
                    dataIndex: 'view_right',
                    width: 55
                }),
                new Ext.ux.grid.CheckColumn({
                    header: this.translation.gettext('Use'),
                    dataIndex: 'use_right',
                    width: 55
                })
            ]
        });

        var editTagDialog = {
            layout: 'border',
            border: false,
            items: [{
                region: 'north',
                xtype: 'columnform',
                border: false,
                autoHeight: true,
                items: [[{
                    columnWidth: 0.8,
                    fieldLabel: this.translation.gettext('Tag Name'), 
                    name: 'name',
                    allowBlank: false,
                    maxLength: 40
                }, {
                    xtype: 'colorfield',
                    columnWidth: 0.2,
                    fieldLabel: this.translation.gettext('Color'),
                    name: 'color'
                }], [{
                    columnWidth: 1,
                    name: 'description',
                    fieldLabel: this.translation.gettext('Description'),
                    anchor: '100%',
                    xtype: 'textarea',
                    height: 150
                }]]
            }, {
                region: 'center',
                xtype: 'tabpanel',
                activeTab: 0,
                deferredRender: false,
                defaults: { autoScroll: true },
                border: true,
                plain: true,
                items: [
                    this.rightsPanel, 
                    contextPanel
                ]
            }]
        };
        
        return editTagDialog;
    },
    
    initComponent: function () {
        this.tag = this.tag ? this.tag : new Tine.Tinebase.Model.Tag({}, 0);
        
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');
        
        Ext.Ajax.request({
            scope: this,
            success: this.onRecordLoad,
            params: {
                method: 'Admin.getTag',
                tagId: this.tag.id
            }
        });
        
        this.rightsStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            id: 'account_id',
            fields: Tine.Admin.Model.TagRight
        });
        
        this.items = this.getFormContents();
        Tine.Admin.Tags.EditDialog.superclass.initComponent.call(this);
    },
    
    onRender: function (ct, position) {
        Tine.widgets.dialog.EditDialog.superclass.onRender.call(this, ct, position);
        
        // generalized keybord map for edit dlgs
        var map = new Ext.KeyMap(this.el, [{
            key: [10, 13], // ctrl + return
            ctrl: true,
            fn: this.handlerApplyChanges.createDelegate(this, [true], true),
            scope: this
        }]);

        this.loadMask = new Ext.LoadMask(ct, {msg: String.format(i18n._('Transferring {0}...'), this.translation.gettext('Tag'))});
        this.loadMask.show();
    },
    
    onRecordLoad: function (response) {
        this.getForm().findField('name').focus(false, 250);
        var recordData = Ext.util.JSON.decode(response.responseText);
        this.updateRecord(recordData);
        
        if (! this.tag.id) {
            this.window.setTitle(this.translation.gettext('Add New Tag'));
        } else {
            this.window.setTitle(String.format(this.translation._('Edit Tag "{0}"'), this.tag.get('name')));
        }
        
        this.loadMask.hide();
    }     
});

/**
 * Admin Tag Edit Popup
 */
Tine.Admin.Tags.EditDialog.openWindow = function (config) {
    config.tag = config.tag ? config.tag : new Tine.Tinebase.Model.Tag({}, 0);
    var window = Tine.WindowFactory.getWindow({
        width: 650,
        height: 400,
        name: Tine.Admin.Tags.EditDialog.prototype.windowNamePrefix + config.tag.id,
        contentPanelConstructor: 'Tine.Admin.Tags.EditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 316:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philip Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         refactor this (don't use Ext.getCmp, etc.)
 */
 
Ext.ns('Tine.Admin.Roles');

/*********************************** MAIN DIALOG ********************************************/

Tine.Admin.Roles.Main = {
    
    // references to crated toolbar and grid panel
    rolesToolbar: null,
    gridPanel: null,
    
    actions: {
        addRole: null,
        editRole: null,
        deleteRole: null
    },
    
    handlers: {
        /**
         * onclick handler for addBtn
         */
        addRole: function(_button, _event) {
            this.openEditWindow(null);
        },

        /**
         * onclick handler for editBtn
         */
        editRole: function(_button, _event) {
            var selectedRows = this.gridPanel.getSelectionModel().getSelections();
            this.openEditWindow(selectedRows[0]);
        },

        /**
         * onclick handler for deleteBtn
         */
        deleteRole: function(_button, _event) {
            Ext.MessageBox.confirm(this.translation.gettext('Confirm'), this.translation.gettext('Do you really want to delete the selected roles?'), function(_button){
                if (_button == 'yes') {
                
                    var roleIds = new Array();
                    var selectedRows = this.gridPanel.getSelectionModel().getSelections();
                    for (var i = 0; i < selectedRows.length; ++i) {
                        roleIds.push(selectedRows[i].id);
                    }
                    
                    roleIds = roleIds;
                    
                    Ext.Ajax.request({
                        url: 'index.php',
                        params: {
                            method: 'Admin.deleteRoles',
                            roleIds: roleIds
                        },
                        text: this.translation.gettext('Deleting role(s)...'),
                        success: function(_result, _request){
                            this.gridPanel.getStore().reload();
                        },
                        failure: function(result, request){
                            Ext.MessageBox.alert(this.translation.gettext('Failed'), this.translation.gettext('Some error occurred while trying to delete the role.'));
                        },
                        scope: this
                    });
                }
            }, this);
        }    
    },
    
    /**
     * open edit window
     * 
     * @param {} record
     */
    openEditWindow: function (record) {
        var popupWindow = Tine.Admin.Roles.EditDialog.openWindow({
            role: record,
            listeners: {
                scope: this,
                'update': function(record) {
                    this.reload();
                }
            }                
        });
    },
    
    /**
     * init roles grid
     */
    initComponent: function() {
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');
        
        this.pageSize = Tine.Tinebase.registry.get('preferences').get('pageSize')
            ? parseInt(Tine.Tinebase.registry.get('preferences').get('pageSize'), 10)
            : 50;
        
        this.actions.addRole = new Ext.Action({
            text: this.translation.gettext('Add Role'),
            disabled: true,
            handler: this.handlers.addRole,
            iconCls: 'action_add',
            scope: this
        });
        
        this.actions.editRole = new Ext.Action({
            text: this.translation.gettext('Edit Role'),
            disabled: true,
            handler: this.handlers.editRole,
            iconCls: 'action_edit',
            scope: this
        });
        
        this.actions.deleteRole = new Ext.Action({
            text: this.translation.gettext('Delete Role'),
            disabled: true,
            handler: this.handlers.deleteRole,
            iconCls: 'action_delete',
            scope: this
        });

    },
    
    displayRolesToolbar: function() {
        
        // if toolbar was allready created set active toolbar and return
        if (this.rolesToolbar)
        {
            Tine.Tinebase.MainScreen.setActiveToolbar(this.rolesToolbar, true);
            return;
        }
        
        var RolesQuickSearchField = new Ext.ux.SearchField({
            id: 'RolesQuickSearchField',
            width:240,
            emptyText: i18n._hidden('enter searchfilter')
        });
        RolesQuickSearchField.on('change', function(){
            this.gridPanel.getStore().load({
                params: {
                    start: 0,
                    limit: this.pageSize
                }
            });
        }, this);
        
        this.rolesToolbar = new Ext.Toolbar({
            canonicalName: ['Role', 'ActionToolbar'].join(Tine.Tinebase.CanonicalPath.separator),
            split: false,
            items: [{
                // create buttongroup to be consistent
                xtype: 'buttongroup',
                items: [
                    Ext.apply(new Ext.Button(this.actions.addRole), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),
                    Ext.apply(new Ext.Button(this.actions.editRole), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),
                    Ext.apply(new Ext.Button(this.actions.deleteRole), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    })
                ]
            } ,
            '->', 
                this.translation.gettext('Search:'), 
                ' ',
                RolesQuickSearchField
            ]
        });

        Tine.Tinebase.MainScreen.setActiveToolbar(this.rolesToolbar, true);
    },

    displayRolesGrid: function() {
        
        // if grid panel was allready created set active content panel and return
        if (this.gridPanel)
        {
            Tine.Tinebase.MainScreen.setActiveContentPanel(this.gridPanel, true);
            return;
        }
        
        if ( Tine.Tinebase.common.hasRight('manage', 'Admin', 'roles') ) {
            this.actions.addRole.setDisabled(false);
        }

        var dataStore = new Ext.data.JsonStore({
            baseParams: {
                method: 'Admin.getRoles'
            },
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Tinebase.Model.Role,
            remoteSort: true
        });
        
        dataStore.setDefaultSort('id', 'asc');

        dataStore.on('beforeload', function(_dataStore, _options) {
            _options = _options || {};
            _options.params = _options.params || {};
            _options.params.query = Ext.getCmp('RolesQuickSearchField').getValue();
        }, this);
        
        // the paging toolbar
        var pagingToolbar = new Ext.PagingToolbar({
            pageSize: this.pageSize,
            store: dataStore,
            displayInfo: true,
            displayMsg: this.translation.gettext('Displaying roles {0} - {1} of {2}'),
            emptyMsg: this.translation.gettext("No roles to display")
        });
        
        // the columnmodel
        var columnModel = new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: [
                { id: 'id', header: this.translation.gettext('ID'), dataIndex: 'id', hidden: true, width: 10 },
                { id: 'name', header: this.translation.gettext('Name'), dataIndex: 'name', width: 50 },
                { id: 'description', header: this.translation.gettext('Description'), dataIndex: 'description' }
            ]
        });
        
        // the rowselection model
        var rowSelectionModel = new Ext.grid.RowSelectionModel({multiSelect:true});

        rowSelectionModel.on('selectionchange', function(_selectionModel) {
            var rowCount = _selectionModel.getCount();

            if ( Tine.Tinebase.common.hasRight('manage', 'Admin', 'roles') ) {
                if(rowCount < 1) {
                    // no row selected
                    this.actions.deleteRole.setDisabled(true);
                    this.actions.editRole.setDisabled(true);
                } else if(rowCount > 1) {
                    // more than one row selected
                    this.actions.deleteRole.setDisabled(false);
                    this.actions.editRole.setDisabled(true);
                } else {
                    // only one row selected
                    this.actions.deleteRole.setDisabled(false);
                    this.actions.editRole.setDisabled(false);
                }
            }
        }, this);
        
        // the gridpanel
        this.gridPanel = new Ext.grid.GridPanel({
            canonicalName: ['Role', 'Grid'].join(Tine.Tinebase.CanonicalPath.separator),
            store: dataStore,
            cm: columnModel,
            tbar: pagingToolbar,     
            autoSizeColumns: false,
            selModel: rowSelectionModel,
            enableColLock:false,
            autoExpandColumn: 'n_family',
            border: false,
            view: new Ext.grid.GridView({
                autoFill: true,
                forceFit:true,
                ignoreAdd: true,
                emptyText: this.translation.gettext('No roles to display')
            })            
        });
        
        this.gridPanel.on('rowcontextmenu', function(_grid, _rowIndex, _eventObject) {
            _eventObject.stopEvent();
            if(!_grid.getSelectionModel().isSelected(_rowIndex)) {
                _grid.getSelectionModel().selectRow(_rowIndex);
            }
            
            if (! this.contextMenu) {
                this.contextMenu = new Ext.menu.Menu({
                    id: 'ctxMenuRoles',
                    plugins: [{
                        ptype: 'ux.itemregistry',
                        key:   'Tinebase-MainContextMenu'
                    }],
                    items: [
                        this.actions.editRole,
                        this.actions.deleteRole,
                        '-',
                        this.actions.addRole 
                    ]
                });
            }
            this.contextMenu.showAt(_eventObject.getXY());
        }, this);
        
        this.gridPanel.on('rowdblclick', function(_gridPar, _rowIndexPar, ePar) {
            if ( Tine.Tinebase.common.hasRight('manage', 'Admin', 'roles') ) {
                var record = _gridPar.getStore().getAt(_rowIndexPar);
                this.openEditWindow(record);
            }
        }, this);

        // add the grid to the layout
        Tine.Tinebase.MainScreen.setActiveContentPanel(this.gridPanel, true);
    },
    
    /**
     * update datastore with node values and load datastore
     */
    loadData: function() 
    {
        var dataStore = this.gridPanel.getStore();
        dataStore.load({ params: { start: 0, limit: this.pageSize } });
    },

    show: function() 
    {
        if (this.rolesToolbar === null || this.gridPanel === null) {
            this.initComponent();
        }

        this.displayRolesToolbar();
        this.displayRolesGrid();

        this.loadData();
    },

    reload: function () {
        if (this.gridPanel) {
            this.gridPanel.getStore().reload.defer(200, this.gridPanel.getStore());
        }
    }
};


/**
 * Model of a right
 */
Tine.Admin.Roles.Right = Ext.data.Record.create([
    {name: 'application_id'},
    {name: 'right'}
]);




/***/ }),

/***/ 317:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philip Schuele <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * TODO         refactor this (don't use Ext.getCmp, etc.)
 */

/*global Ext, Tine, Locale*/

Ext.ns('Tine.Admin.Roles');

/**
 * @namespace   Tine.Admin.Roles
 * @class       Tine.Admin.Roles.EditDialog
 * @extends     Tine.widgets.dialog.EditRecord
 */
Tine.Admin.Roles.EditDialog = Ext.extend(Tine.widgets.dialog.EditRecord, {

    /**
     * @cfg {Tine.Tinebase.Model.Role}
     */
    role: null,
    
    /**
     * @property {Object} holds allRights (possible rights)
     */
    allRights: null,
    
    /**
     * @property {Ext.tree.treePanel}
     */
    rightsTreePanel: null,
    
    windowNamePrefix: 'rolesEditWindow_',
    
    layout: 'fit',
    border: false,
    id: 'roleDialog',
    labelWidth: 120,
    labelAlign: 'top',
    
    /**
     * check if right is set for application and get the record id
     * @private
     */
    getRightId: function (applicationId, right) {
        var id = false,
            result = null;
        
        this.rightsDataStore.each(function (item) {
            if (item.data.application_id === applicationId && item.data.right === right) {
                result = item.id;
                return;
            }
        });
        
        return result;
    },  
    
    handlerApplyChanges: function (button, event, closeWindow) {
        var form = this.getForm();
        
        if (form.isValid()) {
            // get role members
            var roleGrid = Ext.getCmp('roleMembersGrid');

            Ext.MessageBox.wait(this.translation.gettext('Please wait'), this.translation.gettext('Updating Memberships'));
            
            var roleMembers = [];
            this.membersStore.each(function (record) {
                roleMembers.push(record.data);
            });

            // get role rights                
            var roleRights = [],
                rightsStore = this.rightsDataStore;
            
            rightsStore.each(function (record) {
                roleRights.push(record.data);
            });

            // update form               
            form.updateRecord(this.role);

            /*********** save role members & form ************/
            
            Ext.Ajax.request({
                params: {
                    method: 'Admin.saveRole', 
                    roleData: this.role.data,
                    roleMembers: roleMembers,
                    roleRights: roleRights
                },
                timeout: 300000, // 5 minutes
                success: function (response) {
                    this.fireEvent('update', Ext.util.JSON.encode(this.role.data));
                    Ext.MessageBox.hide();
                    if (closeWindow === true) {
                        this.window.close();
                    } else {
                        this.onRecordLoad(response);
                    }
                },
                failure: function (result, request) {
                    Ext.MessageBox.alert(this.translation.gettext('Failed'), this.translation.gettext('Could not save role.'));
                },
                scope: this 
            });
                
            
        } else {
            Ext.MessageBox.alert(this.translation.gettext('Errors'), this.translation.gettext('Please fix the errors noted.'));
        }
    },
    
    handlerDelete: function (button, event) {
        var roleIds = [this.role.id];
            
        Ext.Ajax.request({
            url: 'index.php',
            params: {
                method: 'Admin.deleteRoles', 
                roleIds: roleIds
            },
            text: this.translation.gettext('Deleting role...'),
            success: function (result, request) {
                if (window.opener.Tine.Admin.Roles) {
                    window.opener.Tine.Admin.Roles.Main.reload();
                }
                window.close();
            },
            failure: function (result, request) {
                Ext.MessageBox.alert(this.translation.gettext('Failed'), this.translation.gettext('Some error occurred while trying to delete the role.'));
            } 
        });
    },

    updateRecord: function (roleData) {
        // if roleData is empty (=array), set to empty object because array won't work!
        if (roleData.length === 0) {
            roleData = {};
        }
        this.role = new Tine.Tinebase.Model.Role(roleData, roleData.id ? roleData.id : 0);
        
        this.membersStore.loadData(this.role.get('roleMembers'));
        this.rightsDataStore.loadData(this.role.get('roleRights'));
        this.allRights = this.role.get('allRights');
        this.createRightsTreeNodes();
    },

    /**
     * creates the rights tree
     *
     */
    initRightsTree: function () {
        this.rightsTreePanel = new Ext.tree.TreePanel({
            title: this.translation.gettext('Rights'),
            autoScroll: true,
            rootVisible: false,
            border: false
        });
        
        // sort nodes by text property
        this.treeSorter = new Ext.tree.TreeSorter(this.rightsTreePanel, {
            folderSort: true,
            dir: "asc"
        });
        
        // set the root node
        var treeRoot = new Ext.tree.TreeNode({
            text: 'root',
            draggable: false,
            allowDrop: false,
            id: 'root'
        });

        this.rightsTreePanel.setRootNode(treeRoot);
    },
    
    /**
     * create nodes for rights tree (apps + app rights)
     * 
     * @return {Ext.tree.TreePanel}
     */
    createRightsTreeNodes: function () {
        var treeRoot = this.rightsTreePanel.getRootNode();
        
        var toRemove = [];
        treeRoot.eachChild(function (node) {
            toRemove.push(node);
        });
        
        var expandNode = (this.allRights.length > 5) ? false : true;
        
        // add nodes to tree        
        for (var i = 0; i < this.allRights.length; i += 1) {
            // don't duplicate tree nodes on 'apply changes'
            var remove = toRemove[i] ? toRemove[i].remove() : null;
            this.allRights[i].text = this.translateAppTitle(this.allRights[i].text);
            var node = new Ext.tree.TreeNode(this.allRights[i]);
            node.attributes.application_id = this.allRights[i].application_id;
            node.expanded = expandNode;
            treeRoot.appendChild(node);
            
            // append children          
            if (this.allRights[i].children) {
                for (var j = 0; j < this.allRights[i].children.length; j += 1) {
                    var childData = this.allRights[i].children[j];
                    childData.leaf = true;
                    
                    // check if right is set
                    childData.checked = !!this.getRightId(this.allRights[i].application_id, childData.right);
                    childData.iconCls = "x-tree-node-leaf-checkbox";
                    var child = new Ext.tree.TreeNode(childData);
                    child.attributes.right = childData.right;
                    
                    child.on('checkchange', function (node, checked) {
                        var applicationId = node.parentNode.attributes.application_id;
                    
                        // put it in the storage or remove it                        
                        if (checked) {
                            this.rightsDataStore.add(
                                new Ext.data.Record({
                                    right: node.attributes.right,
                                    application_id: applicationId
                                })
                            );
                        } else {
                            var rightId = this.getRightId(applicationId, node.attributes.right);
                            this.rightsDataStore.remove(this.rightsDataStore.getById(rightId));
                        }   
                    }, this);
                    
                    node.appendChild(child);
                }       
            }
        }     
        
        return this.rightsTreePanel;
    },
    
    /**
     * translate and return app title
     * 
     * TODO try to generalize this fn as this gets used in Tags.js + Applications.js as well 
     *      -> this could be moved to Tine.Admin.Application after Admin js refactoring
     */
    translateAppTitle: function (appName) {
        var app = Tine.Tinebase.appMgr.get(appName);
        return (app) ? app.getTitle() : appName;
    },
    
    /**
     * returns form
     * 
     */
    getFormContents: function () {
        this.accountPickerGridPanel = new Tine.widgets.account.PickerGridPanel({
            title: this.translation.gettext('Members'),
            store: this.membersStore,
            anchor: '100% 100%',
            groupRecordClass: Tine.Admin.Model.Group,
            selectType: 'both',
            selectAnyone: false,
            selectTypeDefault: 'group',
            showHidden: true
        });
        
        this.initRightsTree();
        
        /******* THE edit dialog ********/
        
        var editRoleDialog = {
            layout: 'border',
            border: false,
            items: [{
                region: 'north',
                layout: 'form',
                border: false,
                autoHeight: true,
                items: [{
                    xtype: 'textfield',
                    fieldLabel: this.translation.gettext('Role Name'), 
                    name: 'name',
                    anchor: '100%',
                    allowBlank: false,
                    maxLength: 128
                }, {
                    xtype: 'textarea',
                    name: 'description',
                    fieldLabel: this.translation.gettext('Description'),
                    grow: false,
                    preventScrollbars: false,
                    anchor: '100%',
                    height: 60
                }]
            }, {
                xtype: 'tabpanel',
                plain: true,
                region: 'center',
                activeTab: 0,
                items: [
                    this.accountPickerGridPanel,
                    this.rightsTreePanel
                ]
            }]
        };
        
        return editRoleDialog;
    },
    
    initComponent: function () {
        this.role = this.role ? this.role : new Tine.Tinebase.Model.Role({}, 0);
        
        this.translation = new Locale.Gettext();
        this.translation.textdomain('Admin');
        
        Ext.Ajax.request({
            scope: this,
            success: this.onRecordLoad,
            params: {
                method: 'Admin.getRole',
                roleId: this.role.id
            }
        });
        
        // init role members store
        this.membersStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            id: 'id',
            fields: Tine.Tinebase.Model.Account
        });
        
        // init rights store
        this.rightsDataStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            fields: Tine.Admin.Roles.Right
        });
        
        this.items = this.getFormContents();
        
        Tine.Admin.Groups.EditDialog.superclass.initComponent.call(this);
    },
    
    onRender: function (ct, position) {
        Tine.widgets.dialog.EditDialog.superclass.onRender.call(this, ct, position);
        
        // generalized keybord map for edit dlgs
        var map = new Ext.KeyMap(this.el, [{
            key: [10, 13], // ctrl + return
            ctrl: true,
            fn: this.handlerApplyChanges.createDelegate(this, [true], true),
            scope: this
        }]);

        this.loadMask = new Ext.LoadMask(ct, {msg: String.format(i18n._('Transferring {0}...'), this.translation.gettext('Role'))});
        this.loadMask.show();
    },
    
    onRecordLoad: function (response) {
        this.getForm().findField('name').focus(false, 250);
        var recordData = Ext.util.JSON.decode(response.responseText);
        this.updateRecord(recordData);
        
        if (! this.role.id) {
            this.window.setTitle(this.translation.gettext('Add New Role'));
        } else {
            this.window.setTitle(String.format(this.translation.gettext('Edit Role "{0}"'), this.role.get('name')));
        }
        
        this.getForm().loadRecord(this.role);
        
        this.loadMask.hide();
    }
    
});

/**
 * Roles Edit Popup
 */
Tine.Admin.Roles.EditDialog.openWindow = function (config) {
    config.role = config.role ? config.role : new Tine.Tinebase.Model.Role({}, 0);
    var window = Tine.WindowFactory.getWindow({
        width: 400,
        height: 600,
        name: Tine.Admin.Roles.EditDialog.prototype.windowNamePrefix + config.role.id,
        contentPanelConstructor: 'Tine.Admin.Roles.EditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 318:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.ns('Tine.Admin');

/**
 * @namespace   Tine.widgets.tags
 * @class       Tine.Admin.ApplicationFilter
 * @extends     Tine.widgets.grid.FilterModel
 */
Tine.Admin.ApplicationFilter = Ext.extend(Tine.widgets.grid.FilterModel, {
    /**
     * @cfg {Tine.Tinebase.Application} app
     */
    app: null,
    
    field: 'application_id',
    defaultOperator: 'equals',
    
    /**
     * @private
     */
    initComponent: function() {
        Tine.Admin.ApplicationFilter.superclass.initComponent.call(this);
        
        this.operators = ['equals', 'not'];
        this.label = this.app.i18n._('Application');
    },
    
    /**
     * value renderer
     * 
     * @param {Ext.data.Record} filter line
     * @param {Ext.Element} element to render to 
     */
    valueRenderer: function(filter, el) {
        this.appStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            fields: Tine.Admin.Model.Application
        });
        this.appStore.loadData({
            results:    Tine.Tinebase.registry.get('userApplications'),
            totalcount: Tine.Tinebase.registry.get('userApplications').length
        });
        
        var value = new Ext.form.ComboBox({
            app: this.app,
            name: 'application_id',
            store: this.appStore,
            displayField: 'name',
            valueField: 'id',
            filter: filter,
            width: this.filterValueWidth,
            id: 'tw-ftb-frow-valuefield-' + filter.id,
            value: filter.data.value ? filter.data.value : this.defaultValue,
            mode: 'local',
            renderTo: el
        });
        value.on('specialkey', function(field, e){
             if(e.getKey() == e.ENTER){
                 this.onFiltertrigger();
             }
        }, this);
        
        return value;
    }
});
Tine.widgets.grid.FilterToolbar.FILTERS['admin.application'] = Tine.Admin.ApplicationFilter;



/***/ }),

/***/ 319:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
 */

/*global Ext, Tine*/ 

Ext.ns('Tine.Admin.container');

/**
 * Containers 'mainScreen'
 * 
 * @static
 */
Tine.Admin.container.show = function () {
    var app = Tine.Tinebase.appMgr.get('Admin');
    if (! Tine.Admin.container.gridPanel) {
        Tine.Admin.container.gridPanel = new Tine.Admin.container.GridPanel({
            app: app
        });
    }
    else {
        Tine.Admin.container.gridPanel.loadGridData.defer(100, Tine.Admin.container.gridPanel, []);
    }
    
    Tine.Tinebase.MainScreen.setActiveContentPanel(Tine.Admin.container.gridPanel, true);
    Tine.Tinebase.MainScreen.setActiveToolbar(Tine.Admin.container.gridPanel.actionToolbar, true);
};

/************** models *****************/
Ext.ns('Tine.Admin.Model');

/**
 * Model of a container
 */
Tine.Admin.Model.Container = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.Container.getFieldDefinitions().concat([
    {name: 'note'}
]), {
    appName: 'Admin',
    modelName: 'Container',
    idProperty: 'id',
    titleProperty: 'name',
    // ngettext('Container', 'Containers', n);
    recordName: 'Container',
    recordsName: 'Containers'
});

/**
 * returns default account data
 * 
 * @namespace Tine.Admin.Model.Container
 * @static
 * @return {Object} default data
 */
Tine.Admin.Model.Container.getDefaultData = function () {
    return {
        type: 'shared',
        backend: 'Sql'
    };
};

/************** backend *****************/

Tine.Admin.containerBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'Container',
    recordClass: Tine.Admin.Model.Container,
    idProperty: 'id'
});


/***/ }),

/***/ 320:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
 */
 
/*global Ext, Tine*/

Ext.ns('Tine.Admin.container');

/**
 * @namespace   Tine.Admin.container
 * @class       Tine.Admin.ContainerEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Container Edit Dialog</p>
 * <p>
 * </p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Admin.ContainerEditDialog
 * 
 * TODO add note for personal containers (note is sent to container owner)
 */
Tine.Admin.ContainerEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    windowNamePrefix: 'containerEditWindow_',
    appName: 'Admin',
    recordClass: Tine.Admin.Model.Container,
    recordProxy: Tine.Admin.containerBackend,
    evalGrants: false,
    modelStore: null,
    
    /**
     * executed after record got updated from proxy
     */
    onRecordLoad: function () {
        Tine.Admin.ContainerEditDialog.superclass.onRecordLoad.apply(this, arguments);
        
        // load grants store if editing record
        if (this.record && this.record.id) {
            this.grantsGrid.getStore().loadData({
                results:    this.record.get('account_grants'),
                totalcount: this.record.get('account_grants').length
            });
        }
    },    
    
    /**
     * executed when record gets updated from form
     */
    onRecordUpdate: function () {
        Tine.Admin.ContainerEditDialog.superclass.onRecordUpdate.apply(this, arguments);
        
        // get grants from grants grid
        this.record.set('account_grants', '');
        var grants = [];
        this.grantsGrid.getStore().each(function(grant){
            grants.push(grant.data);
        });
        this.record.set('account_grants', grants);
    },
    
    /**
     * create grants store + grid
     * 
     * @return {Tine.widgets.container.GrantsGrid}
     */
    initGrantsGrid: function () {
        this.grantsGrid = new Tine.widgets.container.GrantsGrid({
            flex: 1,
            grantContainer: this.record.data,
            alwaysShowAdminGrant: true,
            showHidden: true
        });
        
        return this.grantsGrid;
    },

    /**
     * returns dialog
     */
    getFormItems: function () {
        var userApplications = Tine.Tinebase.registry.get('userApplications');
        this.appStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            fields: Tine.Admin.Model.Application
        });

        this.appStore.loadData({
            results: userApplications,
            totalcount: userApplications.length
        });

        this.modelStore = new Ext.data.ArrayStore({
            idIndex: 0,
            fields: [{name: 'value'}, {name: 'name'}]
        });

        return {
            layout: 'vbox',
            layoutConfig: {
                align: 'stretch',
                pack: 'start'
            },
            border: false,
            items: [{
                xtype: 'columnform',
                border: false,
                autoHeight: true,
                items: [[{
                    columnWidth: 0.2,
                    fieldLabel: this.app.i18n._('Name'), 
                    name: 'name',
                    allowBlank: false,
                    maxLength: 255
                }, {
                    xtype: 'combo',
                    readOnly: this.record.id != 0,
                    store: this.appStore,
                    columnWidth: 0.2,
                    name: 'application_id',
                    displayField: 'name',
                    valueField: 'id',
                    fieldLabel: this.app.i18n._('Application'),
                    mode: 'local',
                    anchor: '100%',
                    allowBlank: false,
                    forceSelection: true,
                    listeners: {
                        scope: this,
                        'select': function (combo, rec) {
                            this.modelStore.loadData(this.getApplicationModels(rec, false));
                            Ext.getCmp('modelCombo').setValue('');
                        }
                    }
                },
                {
                    xtype: 'combo',
                    readOnly: this.record.id != 0,
                    store: this.modelStore,
                    columnWidth: 0.2,
                    name: 'model',
                    displayField: 'name',
                    valueField: 'value',
                    fieldLabel: this.app.i18n._('Model'),
                    mode: 'local',
                    anchor: '100%',
                    allowBlank: false,
                    forceSelection: true,
                    editable: false,
                    id: 'modelCombo'
                }, {
                    xtype: 'combo',
                    columnWidth: 0.2,
                    name: 'type',
                    fieldLabel: this.app.i18n._('Type'),
                    store: [['personal', this.app.i18n._('personal')], ['shared', this.app.i18n._('shared')]],
                    listeners: {
                        scope: this,
                        select: function (combo, record) {
                            this.getForm().findField('note').setDisabled(record.data.field1 === 'shared');
                        }
                    },
                    mode: 'local',
                    anchor: '100%',
                    allowBlank: false,
                    forceSelection: true
                }, {
                    columnWidth: 0.1,
                    fieldLabel: this.app.i18n._('Order'),
                    name: 'order',
                    value: 0
                }, {
                    xtype: 'colorfield',
                    columnWidth: 0.1,
                    fieldLabel: this.app.i18n._('Color'),
                    name: 'color'
                }]]
            }, 
                this.initGrantsGrid(), {
                    emptyText: this.app.i18n._('Note for Owner'),
                    disabled: this.record.get('type') == 'shared',
                    xtype: 'textarea',
                    border: false,
                    autoHeight: true,
                    name: 'note'
                }
               ]
        };
    }
});

/**
 * Container Edit Popup
 * 
 * @param   {Object} config
 * @return  {Ext.ux.Window}
 */
Tine.Admin.ContainerEditDialog.openWindow = function (config) {
    var window = Tine.WindowFactory.getWindow({
        width: 700,
        height: 400,
        name: Tine.Admin.ContainerEditDialog.prototype.windowNamePrefix + Ext.id(),
        contentPanelConstructor: 'Tine.Admin.ContainerEditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 321:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */
Ext.ns('Tine.Admin.container');


/**
 * Container grid panel
 * 
 * @namespace   Tine.Admin.container
 * @class       Tine.Admin.container.GridPanel
 * @extends     Tine.widgets.grid.GridPanel
 */
Tine.Admin.container.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    
    /**
     * @cfg
     */
    newRecordIcon: 'admin-action-add-container',
    recordClass: Tine.Admin.Model.Container,
    recordProxy: Tine.Admin.containerBackend,
    defaultSortInfo: {field: 'name', direction: 'ASC'},
    evalGrants: false,
    gridConfig: {
        autoExpandColumn: 'name'
    },
    
    /**
     * initComponent
     */
    initComponent: function() {
        this.gridConfig.cm = this.getColumnModel();
        Tine.Admin.container.GridPanel.superclass.initComponent.call(this);
    },
    
    /**
     * returns column model
     * 
     * @return Ext.grid.ColumnModel
     * @private
     */
    getColumnModel: function() {
        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                hidden: true,
                resizable: true
            },
            columns: this.getColumns()
        });
    },
    
    /**
     * returns columns
     * @private
     * @return Array
     */
    getColumns: function(){
        return [
            { header: this.app.i18n._('ID'), id: 'id', dataIndex: 'id', width: 50},
            { header: this.app.i18n._('Container Name'), id: 'name', dataIndex: 'name', hidden: false, width: 200},
            { header: this.app.i18n._('Application'), id: 'application_id', dataIndex: 'application_id', hidden: false, width: 100, renderer: this.appRenderer.createDelegate(this)},
            { header: this.app.i18n._('Type'), id: 'type', dataIndex: 'type', hidden: false, width: 80, renderer: this.typeRenderer.createDelegate(this)},
            { header: this.app.i18n._('Container Order'), id: 'order', dataIndex: 'order', hidden: true, width: 200}
        ];
    },
    
    /**
     * returns application name
     * 
     * @param {Object} value
     * @return {String}
     */
    appRenderer: function(value) {
        return this.app.i18n._(value.name);
    },
    
    /**
     * returns translated type
     * 
     * @param {Object} value
     * @return {String}
     */
    typeRenderer: function(value) {
        return this.app.i18n._(value);
    },
    
    /**
     * initialises filter toolbar
     */
    initFilterPanel: function() {
        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
            filterModels: [
                {label: this.app.i18n._('Container'),       field: 'query',    operators: ['contains']},
                {label: this.app.i18n._('Type'),            field: 'type',     operators: ['contains']},
                {filtertype: 'admin.application', app: this.app}
            ],
            defaultFilter: 'query',
            filters: [
                {field: 'type', operator: 'equals', value: 'shared'}
            ],
            plugins: [
                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
            ]
        });
        this.plugins = this.plugins || [];
        this.plugins.push(this.filterToolbar);
    }
});


/***/ }),

/***/ 322:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
 */

/*global Ext, Tine*/ 

Ext.ns('Tine.Admin.customfield');

/**
 * Customfields 'mainScreen'
 * 
 * @static
 */
Tine.Admin.customfield.show = function () {
    var app = Tine.Tinebase.appMgr.get('Admin');
    if (! Tine.Admin.customfield.gridPanel) {
        Tine.Admin.customfield.gridPanel = new Tine.Admin.customfield.GridPanel({
            app: app
        });
    }
    else {
        Tine.Admin.customfield.gridPanel.loadGridData.defer(100, Tine.Admin.customfield.gridPanel, []);
    }
    
    Tine.Tinebase.MainScreen.setActiveContentPanel(Tine.Admin.customfield.gridPanel, true);
    Tine.Tinebase.MainScreen.setActiveToolbar(Tine.Admin.customfield.gridPanel.actionToolbar, true);
};

/************** models *****************/
Ext.ns('Tine.Admin.Model');

/**
 * Model of a customfield
 */
Tine.Admin.Model.Customfield = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.Customfield.prototype.fields.items, {
    appName: 'Admin',
    modelName: 'Customfield',
    idProperty: 'id',
    titleProperty: 'name',
    // ngettext('Customfield', 'Customfields', n);
    recordName: 'Customfield',
    recordsName: 'Customfields'
});

/************** backend *****************/

Tine.Admin.customfieldBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Admin',
    modelName: 'Customfield',
    recordClass: Tine.Admin.Model.Customfield,
    idProperty: 'id'
});


/***/ }),

/***/ 323:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011-2012 Metaways Infosystems GmbH (http://www.metaways.de)
 */
 
/*global Ext, Tine*/

Ext.ns('Tine.Admin.customfield');

/**
 * @namespace   Tine.Admin.customfield
 * @class       Tine.Admin.CustomfieldEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Customfield Edit Dialog</p>
 * <p>
 * </p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Admin.CustomfieldEditDialog
 * 
 */
Tine.Admin.CustomfieldEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
    
    /**
     * @private
     */
    windowNamePrefix: 'customfieldEditWindow_',
    appName: 'Admin',
    recordClass: Tine.Admin.Model.Customfield,
    recordProxy: Tine.Admin.customfieldBackend,
    evalGrants: false,
    modelStore: null,
    
    /**
     * definition properties for cusomfield
     * @type {Array}
     */
    definitionFields: ['label', 'type', 'value_search', 'length', 'required'],
    
    /**
     * ui properties for customfield
     * @type {Array}
     */
    uiconfigFields: ['order', 'group', 'tab'],
    
    /**
     * type of field with stores
     * @type {Array}
     */
    fieldsWithStore: ['record', 'keyField',  'recordList'],
    
    /**
     * currently selected field type
     * @type 
     */
    fieldType: null,
        
    /**
     * executed after record got updated from proxy
     *  - load values for customfield definition and ui
     */
    onRecordLoad: function () {
        Tine.Admin.CustomfieldEditDialog.superclass.onRecordLoad.apply(this, arguments);
        
        // get definition
        if (this.rendered && this.record.get('definition')) {
            this.fieldType = this.record.get('definition').type;
            
            // load definition values
            Ext.each(this.definitionFields, function (name) {
                this.getForm().findField(name).setValue(this.record.get('definition')[name]);
            }, this);
            
            // load ui config values
            Ext.each(this.uiconfigFields, function (name) {
                this.getForm().findField(name).setValue(this.record.get('definition').uiconfig[name]);
            }, this);
            
            // load specific values for fields with store
            if (this.record.get('definition')[this.fieldType + 'Config']) {
                this[this.fieldType + 'Config'] = this.record.get('definition')[this.fieldType + 'Config'];
            }
        }
    },    
    
    /**
     * executed when record gets updated from form
     *  - get values for customfield definition and ui
     */
    onRecordUpdate: function () {
        Tine.Admin.CustomfieldEditDialog.superclass.onRecordUpdate.apply(this, arguments);
        
        // field definition
        this.record.data.definition = {
            uiconfig: {}
        };
        
        // save definition
        Ext.each(this.definitionFields, function (name) {
            var field = this.getForm().findField(name);
            
            if (! field.disabled && (name !== 'value_search' || (name === 'value_search' && field.getValue() == 1))) {
                this.record.data.definition[name] = field.getValue();
            }
        }, this);
        
        // save ui config
        Ext.each(this.uiconfigFields, function (name) {
            this.record.data.definition.uiconfig[name] = this.getForm().findField(name).getValue();;
        }, this);
        
        // set specific values for fields with stores
        Ext.each(this.fieldsWithStore, function (field) {
            if (this.fieldsWithStore.indexOf(this.fieldType) !== -1 && this[field + 'Config']) {
                this.record.data.definition[field + 'Config'] = this[field + 'Config'];
            }
        }, this);
    },
    
    /**
     * Apply changes handler
     *  - validate some additional data before saving
     * 
     * @param {Ext.Button} button
     * @param {Ext.EventObject} event
     * @param {Boolean} closeWindow
     */
    onApplyChanges: function () {
        if (this.fieldsWithStore.indexOf(this.fieldType) !== -1 && ! this[this.fieldType + 'Config']) {
            Ext.Msg.alert(i18n._('Errors'), this.app.i18n._('Please configure store for this field type'));
            return;
        }
        
        Tine.Admin.CustomfieldEditDialog.superclass.onApplyChanges.apply(this, arguments);
    },
    
    /**
     * Called on type combo select
     * 
     * @param {Ext.form.Combobox}   combo
     * @param {Ext.data.Recod}      record
     * @param {Int}                 index
     */
    onTypeComboSelect: function (combo, record, index) {
        this.fieldType = combo.getValue();
        
        this.getForm().findField('length').setDisabled(this.fieldType !== 'string');
        this.getForm().findField('value_search').setValue(this.fieldType === 'searchcombo' ? 1 : 0);
        this.configureStoreBtn.setDisabled(this.fieldsWithStore.indexOf(this.fieldType) === -1);
    },
    
    /**
     * Set field with store config
     */ 
    onStoreWindowOK: function () {
        if (this[this.fieldType + 'Store'].isValid()) {
            if (this.fieldType == 'record' || this.fieldType == 'recordList') {
                this[this.fieldType + 'Config'] = {
                    value: {
                        records: this[this.fieldType + 'Store'].getValue()
                    }
                };
            } else {
                this[this.fieldType + 'Config'] = {value: this[this.fieldType + 'Store'].getValue()};
            }
             
            this.onStoreWindowClose();
        }
    },
    
    /**
     * Close store Window
     */
    onStoreWindowClose: function () {
        this.storeWindow.purgeListeners();
        this.storeWindow.close();
    },
    
    /**
     * Create store/grid for keyFields
     * 
     * @returns {Tine.widgets.grid.KeyFieldGridPanel}
     */
    initKeyFieldStore: function () {

        this[this.fieldType + 'Store'] =  new Tine.Tinebase.widgets.keyfield.ConfigGrid({});

        var configValue = ! Ext.isEmpty(this.record.get('definition')) && this.record.get('definition')[this.fieldType + 'Config']
            ? this.record.get('definition')[this.fieldType + 'Config'].value
            : null;

        if (this.record.id != 0 && configValue) {
            this[this.fieldType + 'Store'].setValue(configValue);
        }

        return this[this.fieldType + 'Store'];
    },
    
    /**
     * Create store for record field
     * 
     * @returns {Ext.Panel}
     */
    initRecordStore: function () {
        Tine.log.info('Initialize record store config');
        
        var self = this;
               
        this[this.fieldType + 'Store'] = new Ext.FormPanel({
            labelAlign: 'top',
            frame: true,
            border: false,
            defaults: {anchor: '100%'},
            bodyStyle: 'padding: 15px',
            items:[{
                xtype: 'combo',
                store: this.appStore,
                name: 'application_id',
                displayField: 'name',
                valueField: 'id',
                fieldLabel: this.app.i18n._('Application'),
                mode: 'local',
                forceSelection: true,
                editable: false,
                listeners: {
                    scope: this,
                    'select': function (combo, rec) {
                        // load combo with found models for selected application
                        this[this.fieldType + 'Store'].items.get(1).store.loadData(this.getApplicationModels(rec, false));
                    }
                }
            }, {
                xtype: 'combo',
                store: new Ext.data.ArrayStore({
                    idIndex: 0,  
                    fields: ['recordClass', 'recordName']
                }),
                name: 'recordClass',
                displayField: 'recordName',
                valueField: 'recordClass',
                fieldLabel: this.app.i18n._('Record Class'),
                mode: 'local',
                forceSelection: false,
                editable: true,
                allowBlank: false
            }],
            setValue: function (data) {
                var parts = data.split('.'), // e.g Tine.Admin.Model.Group
                    app   = Tine.Tinebase.appMgr.get(parts[1]);
                
                // set value for application combo
                this.items.get(0).setValue(app.id);
                
                // load records based on application combo and set value
                this.items.get(1).store.loadData(self.getApplicationModels(app.appName, false));
                this.items.get(1).setValue(data);
                
            },
            getValue: function () {
                return this.items.get(1).getValue();
            },
            isValid: function () {
                try {
                    var model = eval(this.items.get(1).getValue());
                } catch (e) {
                    Ext.Msg.alert(i18n._('Errors'), self.app.i18n._('Given record class not found'));
                    return false;
                }
                
                return true;
            }
        });
        
        /**
         * Load values if exists in field definition
         */
        var configValue = ! Ext.isEmpty(this.record.get('definition')) && this.record.get('definition')[this.fieldType + 'Config'] 
            ? this.record.get('definition')[this.fieldType + 'Config'].value 
            : null;
            
        if (this.record.id != 0 && configValue) {
            this[this.fieldType + 'Store'].setValue(configValue.records);
        }
        
        return this[this.fieldType + 'Store'];
    },

    initRecordListStore: function () {
        return this.initRecordStore();
    },
    
    /**
     * Show window for configuring field store
     */
    showStoreWindow: function () {
        this.storeWindow = Tine.WindowFactory.getWindow({
            modal: true, // this needs to be modal atm, popup does not work due to issues with this in tineInit.js
            width: 500,
            height: 320,
            border: false,
            items: this['init' + (this.fieldType.charAt(0).toUpperCase() + this.fieldType.substr(1)) + 'Store'](),
            fbar: ['->', {
                text: i18n._('Cancel'),
                minWidth: 70,
                scope: this,
                handler: this.onStoreWindowClose,
                iconCls: 'action_cancel'
            }, {
                text: i18n._('OK'),
                minWidth: 70,
                scope: this,
                handler: this.onStoreWindowOK,
                iconCls: 'action_applyChanges'
            }]
        });
    },
    
    /**
     * returns dialog
     */
    getFormItems: function () {
        this.appStore = new Ext.data.JsonStore({
            root: 'results',
            totalProperty: 'totalcount',
            fields: Tine.Admin.Model.Application
        });

        this.appStore.loadData({
            results:    Tine.Tinebase.registry.get('userApplications'),
            totalcount: Tine.Tinebase.registry.get('userApplications').length
        });

        this.appStore.each(function (app) {
            if (this.getApplicationModels(app, true).length == 0) {
                this.appStore.remove(app);
                return;
            }

            var curApp =  Tine.Tinebase.appMgr.get(app.get('name'));
            var curTitle = curApp ? curApp.getTitle() : '';

            app.set('i18nName', curTitle);
        }, this);

        this.modelStore = new Ext.data.ArrayStore({
            idIndex: 0,
            fields: [{name: 'value'}, {name: 'name'}]
        });

        this.configureStoreBtn = new Ext.Button({
            columnWidth: 0.4,
            fieldLabel: '&#160;',
            xtype: 'button',
            iconCls: 'admin-node-customfields-store',
            text: this.app.i18n._('Configure store'),
            disabled: this.record.id == 0 || this.fieldsWithStore.indexOf(this.record.get('definition').type) === -1,
            scope: this,
            handler: this.showStoreWindow
        });

        return {
            layout: 'vbox',
            layoutConfig: {
                align: 'stretch',
                pack: 'start'
            }, 
            border: false,
            items: [{
                xtype: 'columnform',
                border: false,
                autoHeight: true,
                items: [[{
                    xtype: 'combo',
                    readOnly: this.record.id != 0,
                    store: this.appStore,
                    columnWidth: 0.5,
                    name: 'application_id',
                    displayField: 'i18nName',
                    valueField: 'id',
                    scope: this,
                    fieldLabel: this.app.i18n._('Application'),
                    mode: 'local',
                    anchor: '100%',
                    allowBlank: false,
                    forceSelection: true,
                    editable: false,
                    listeners: {
                        scope: this,
                        'select': function (combo, rec) {
                            // add models for select application
                            this.modelStore.loadData(this.getApplicationModels(rec, true));
                            Ext.getCmp('cfModelCombo').setValue(this.modelStore.getAt(0).get('value'));
                        }
                    }
                }, {
                    xtype: 'combo',
                    readOnly: this.record.id != 0,
                    store: this.modelStore,
                    columnWidth: 0.5,
                    name: 'model',
                    displayField: 'name',
                    valueField: 'value',
                    fieldLabel: this.app.i18n._('Model'),
                    mode: 'local',
                    anchor: '100%',
                    allowBlank: false,
                    forceSelection: true,
                    editable: false,
                    id: 'cfModelCombo'
                }]]
            }, {
                xtype: 'fieldset',
                bodyStyle: 'padding: 5px',
                margins: {top: 5, right: 0, bottom: 0, left: 0},
                title: this.app.i18n._('Custom field definition'),
                labelAlign: 'top',
                defaults: {anchor: '100%'},
                items: [{
                    xtype: 'columnform',
                    border: false,
                    items: [[{
                        columnWidth: 0.6,
                        xtype: 'combo',
                        readOnly: this.record.id != 0,
                        store: [
                            ['string', this.app.i18n._('Text')],
                            ['textarea', this.app.i18n._('Textarea')],
                            ['integer', this.app.i18n._('Number')],
                            ['date', this.app.i18n._('Date')],
                            ['datetime', this.app.i18n._('DateTime')],
                            ['time', this.app.i18n._('Time')],
                            ['boolean', this.app.i18n._('Boolean')],
                            ['searchcombo', this.app.i18n._('Search Combo')],
                            ['keyField', this.app.i18n._('Key Field')],
                            ['record', this.app.i18n._('Record')],
                            ['recordList', this.app.i18n._('Record List')]
                        ],
                        name: 'type',
                        fieldLabel: this.app.i18n._('Type'),
                        mode: 'local',
                        allowBlank: false,
                        editable: false,
                        forceSelection: true,
                        listeners: {
                            scope: this,
                            'select': this.onTypeComboSelect
                        }
                    }, this.configureStoreBtn]]
                }, {
                    xtype: 'textfield',
                    fieldLabel: this.app.i18n._('Name'), 
                    name: 'name',
                    allowBlank: false,
                    maxLength: 50
                }, {
                    xtype: 'textfield',
                    fieldLabel: this.app.i18n._('Label'), 
                    name: 'label',
                    allowBlank: false,
                    maxLength: 50
                }, {
                    xtype: 'numberfield',
                    fieldLabel: this.app.i18n._('Length'),
                    name: 'length',
                    disabled: this.record.id == 0 || this.record.get('definition').type !== 'string'
                }, {
                    xtype: 'checkbox',
                    fieldLabel: this.app.i18n._('Required'),
                    name: 'required'
                }]
            }, {
                xtype: 'fieldset',
                bodyStyle: 'padding: 5px',
                margins: {top: 5, right: 0, bottom: 0, left: 0},
                title: this.app.i18n._('Custom field additional properties'),
                labelAlign: 'top',
                defaults: {anchor: '100%'},
                items: [{
                    xtype: 'textfield',
                    fieldLabel: this.app.i18n._('Tab Panel'),
                    name: 'tab',
                    maxLength: 50
                }, {
                    xtype: 'textfield',
                    fieldLabel: this.app.i18n._('Group'), 
                    name: 'group',
                    maxLength: 50
                }, {
                    xtype: 'textfield',
                    fieldLabel: this.app.i18n._('Order'),
                    name: 'order',
                    maxLength: 50
                }]
            }, {
                xtype: 'hidden',
                name: 'value_search',
                value: 0
            }]
        };
    },
    
    /**
     * is form valid?
     * 
     * @return {Boolean}
     */
    isValid: function() {
        var result = Tine.Admin.UserEditDialog.superclass.isValid.call(this);

        if (! this.record.id && this.customFieldExists()) {
            result = false;
            this.getForm().markInvalid([{
                id: 'name',
                msg: this.app.i18n._("Customfield already exists. Please choose another name.")
            }]);
        }
        
        return result;
    },
    
    /**
     * check if customfield name already exists for this app
     * 
     * @return {Boolean}
     */
    customFieldExists: function() {
        var applicationField = this.getForm().findField('application_id'),
            store = applicationField.getStore(),
            app = store.getById(applicationField.getValue()),
            cfName = this.getForm().findField('name').getValue(),
            cfExists = false;
        
        if (app && cfName) {
            var customfieldsOfApp = Tine[app.get('name')].registry.get('customfields');
            Ext.each(customfieldsOfApp, function(cfConfig) {
                if (cfName === cfConfig.name) {
                    cfExists = true;
                }
            }, this);
        }
        
        return cfExists;
    }
});

/**
 * Customfield Edit Popup
 * 
 * @param   {Object} config
 * @return  {Ext.ux.Window}
 */
Tine.Admin.CustomfieldEditDialog.openWindow = function (config) {
    var window = Tine.WindowFactory.getWindow({
        width: 500,
        height: 500,
        name: Tine.Admin.CustomfieldEditDialog.prototype.windowNamePrefix + Ext.id(),
        contentPanelConstructor: 'Tine.Admin.CustomfieldEditDialog',
        contentPanelConstructorConfig: config
    });
    return window;
};


/***/ }),

/***/ 324:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */
Ext.ns('Tine.Admin.customfield');


/**
 * Customfield grid panel
 * 
 * @namespace   Tine.Admin.customfield
 * @class       Tine.Admin.customfield.GridPanel
 * @extends     Tine.widgets.grid.GridPanel
 */
Tine.Admin.customfield.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    
    /**
     * @cfg
     */
    newRecordIcon: 'admin-action-add-customfield',
    recordClass: Tine.Admin.Model.Customfield,
    recordProxy: Tine.Admin.customfieldBackend,
    defaultSortInfo: {field: 'name', direction: 'ASC'},
    evalGrants: false,
    copyEditAction: true,
    gridConfig: {
        autoExpandColumn: 'name'
    },
    
    /**
     * initComponent
     */
    initComponent: function() {
        this.gridConfig.cm = this.getColumnModel();
        Tine.Admin.customfield.GridPanel.superclass.initComponent.call(this);
    },
    
    /**
     * returns column model
     * 
     * @return Ext.grid.ColumnModel
     * @private
     */
    getColumnModel: function() {
        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                hidden: true,
                resizable: true
            },
            columns: this.getColumns()
        });
    },
    
    /**
     * returns columns
     * @private
     * @return Array
     */
    getColumns: function(){
        return [
            { header: this.app.i18n._('ID'), id: 'id', dataIndex: 'id', width: 50},
            { header: this.app.i18n._('Label'), id: 'label', dataIndex: 'definition', hidden: false, width: 100, renderer: this.labelRenderer.createDelegate(this)},
            { header: this.app.i18n._('Name'), id: 'name', dataIndex: 'name', hidden: false, width: 75},
            { header: this.app.i18n._('Type'), id: 'xtype', dataIndex: 'definition', hidden: false, width: 75, renderer: this.typeRenderer.createDelegate(this)},
            { header: this.app.i18n._('Application'), id: 'application_id', dataIndex: 'application_id', hidden: false, width: 100, renderer: this.appRenderer.createDelegate(this)},
            { header: this.app.i18n._('Model'), id: 'model', dataIndex: 'model', hidden: false, width: 100}
        ];
    },
    
    /**
     * returns label name
     * 
     * @param {Object} value
     * @return {String}
     */
    labelRenderer: function(value) {
        return this.app.i18n._(value.label);
    },
    
    /**
     * returns type name
     * 
     * @param {Object} value
     * @return {String}
     */
    typeRenderer: function(value) {
        return this.app.i18n._(value.type);
    },
    
    /**
     * returns application name
     * 
     * @param {Object} value
     * @return {String}
     */
    appRenderer: function(value) {
        return this.app.i18n._(value.name);
    },
       
    /**
     * initialises filter toolbar
     */
    initFilterPanel: function() {
        this.filterToolbar = new Tine.widgets.grid.FilterToolbar({
            filterModels: [
                {label: this.app.i18n._('Customfield'),       field: 'query',    operators: ['contains']},
                {filtertype: 'admin.application', app: this.app}
            ],
            defaultFilter: 'query',
            filters: [
            ],
            plugins: [
                new Tine.widgets.grid.FilterToolbarQuickFilterPlugin()
            ]
        });
        this.plugins = this.plugins || [];
        this.plugins.push(this.filterToolbar);
    },
    
    /**
     * on update after edit
     * 
     * @param {String|Tine.Tinebase.data.Record} record
     */
    onUpdateRecord: function (record) {
        Tine.Admin.customfield.GridPanel.superclass.onUpdateRecord.apply(this, arguments);
        
        Tine.Tinebase.common.confirmApplicationRestart();
    },
    
    /**
     * do something after deletion of records
     * - reload the store
     * 
     * @param {Array} [ids]
     */
    onAfterDelete: function (ids) {
        Tine.Admin.customfield.GridPanel.superclass.onAfterDelete.apply(this, arguments);
        
        Tine.Tinebase.common.confirmApplicationRestart();
    },
    
    deleteRecords: function(sm, records) {
        // directly remove records from the store (only for non-filter-selection)
        if (Ext.isArray(records)) {
            Ext.each(records, function(record) {
                this.store.remove(record);
            });
            // if nested in an editDialog, just change the parent record
            if (this.editDialog) {
                var items = [];
                this.store.each(function(item) {
                    items.push(item.data);
                });
                this.editDialog.record.set(this.editDialogRecordProperty, items);
                this.editDialog.fireEvent('updateDependent');
                return;
            }
        }

        if (this.recordProxy) {
            if (this.usePagingToolbar) {
                this.pagingToolbar.refresh.disable();
            }

            var i18nItems = this.app.i18n.n_hidden(this.recordClass.getMeta('recordName'), this.recordClass.getMeta('recordsName'), records.length),
                recordIds = [].concat(records).map(function(v){ return v.id; });

            this.deleteQueue = this.deleteQueue.concat(recordIds);

            var options = {
                scope: this,
                success: function() {
                    this.refreshAfterDelete(recordIds);
                    this.onAfterDelete(recordIds);
                },
                failure: function (exception) {
                    if (exception.code == 703) {
                        Ext.Msg.confirm(this.app.i18n._('This custom field is still in use!'),
                            this.app.i18n._('Are you sure you want to delete them?'),
                            function(btn) {
                                if (btn == 'yes') {
                                    this.recordProxy.deleteRecords(records, options, {'context': { 'skipUsageCheck': true }});
                                } else {
                                    this.refreshAfterDelete(recordIds);
                                    this.loadGridData();
                                }
                            }, this);
                    } else {
                        this.refreshAfterDelete(recordIds);
                        this.loadGridData();
                        Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
                    }
                }
            };
        
        this.recordProxy.deleteRecords(records, options);
        }
    }
});


/***/ }),

/***/ 325:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiß <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2015 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */
Ext.ns('Tine.Admin.config');


/**
 * config edit field manager
 *
 *  @singleton
 */
Tine.Admin.config.FieldManager = function() {
    var items = {};

    return {

        /**
         * create field for given configRecord value
         *
         * @param configRecord
         * @param options
         * @returns Ext.form.Field|null
         */
        create: function (configRecord, options) {
            var type = configRecord.get('type'),
                constr = Ext.form.TextField;

            if (items.hasOwnProperty(type)) {
                constr = items[type]
            } else {
                switch (type) {
                    case 'string':
                        constr = Ext.form.TextField;
                        break;

                    case 'bool':
                    case 'boolean':
                        options = Ext.apply({
                            mode: 'local',
                            forceSelection: true,
                            allowEmpty: false,
                            triggerAction: 'all',
                            editable: false,
                            store: [[true, i18n._('Yes')], [false, i18n._('No')]]
                        }, options);
                        constr = Ext.form.ComboBox;
                        break;

                    case 'keyField':
                        var store = [];
                        Ext.each(configRecord.get('options')['records'], function(record) {
                            store.push([record.id, options.app.i18n._hidden(record.value)]);
                        });

                        options = Ext.apply({
                            mode: 'local',
                            forceSelection: true,
                            allowEmpty: false,
                            triggerAction: 'all',
                            editable: false,
                            store: store
                        }, options);
                        constr = Ext.form.ComboBox;
                        break;

                    case 'keyFieldConfig':
                        constr = Tine.Tinebase.widgets.keyfield.ConfigField;
                        break;

                    default:
                        constr = null;
                        break;
                }
            }

            return Ext.isFunction(constr) ? new constr(options) : null;

        },

        /**
         * register editor field for given config
         *
         *  @static
         *  @param type string
         *  @param constructor Function
         */
        register: function (type, constructor) {
            items[type] = constructor;
        }
    };
}();

/***/ }),

/***/ 326:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiß <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2015 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */
Ext.ns('Tine.Admin.config');

/**
 * config grid panel
 *
 * @namespace   Tine.Admin.config
 * @class       Tine.Admin.config.GridPanel
 * @extends     Tine.widgets.grid.GridPanel
 */
Tine.Admin.config.GridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {

    /**
     * app to configure with this config panel
     * @cfg {Tine.Tinebase.Application}
     */
    configApp: null,

    recordClass: Tine.Admin.Model.Config,
    defaultSortInfo: {field: 'name', direction: 'ASC'},

    evalGrants: false,

    initFilterPanel: Ext.emptyFn,
    onRowDblClick: Ext.emptyFn,

    /**
     * initComponent
     */
    initComponent: function() {
        var me = this;

        this.recordProxy = new Tine.Tinebase.data.RecordProxy({
            recordClass: this.recordClass
        });

        if (this.appName && !this.configApp) {
            this.configApp = Tine.Tinebase.appMgr.get(this.appName);
        }

        this.app = Tine.Tinebase.appMgr.get('Admin');
        this.title = this.app.i18n._("Config");

        this.gridConfig = {
            autoExpandColumn: 'value',
            gridType: Ext.grid.EditorGridPanel,
            clicksToEdit: 'auto',
        };

        this.detailsPanel = new Tine.widgets.grid.DetailsPanel({
            singleRecordPanel: new Ext.ux.display.DisplayPanel({
                layout: 'fit',
                border: false,
                items: [{
                    cls: 'x-ux-display-background-border',
                    fieldLabel: me.app.i18n.gettext('Description'),
                    name: 'description',
                    xtype: 'ux.displaytextarea',
                    renderer: Tine.Tinebase.common.i18nRenderer.createDelegate(me.configApp.i18n)
                }]
            })
        });


        this.gridConfig.columns = [{
            id: 'name',
            header: this.app.i18n._("Name"),
            width: 150,
            sortable: true,
            dataIndex: 'name'
        },{
            id: 'label',
            header: this.app.i18n._("Label"),
            width: 150,
            sortable: true,
            dataIndex: 'label',
            renderer: Tine.Tinebase.common.i18nRenderer.createDelegate(this.configApp.i18n)
        }, {
            id: 'value',
            header: this.app.i18n._("Value"),
            width: 150,
            sortable: true,
            dataIndex: 'value',
            renderer: this.valueRenderer.createDelegate(this),
            editable: true
        }];

        this.supr().initComponent.call(this);

        this.getGrid().on('beforeedit', this.onBeforeValueEdit, this);
        this.getGrid().on('afteredit', this.onAfterValuerEdit, this);
        this.action_editInNewWindow.setHidden(true);
        this.action_addInNewWindow.setHidden(true);
    },

    /**
     * @param o
         grid - This grid
         record - The record being edited
         field - The field name being edited
         value - The value for the field being edited.
         row - The grid row index
         column - The grid column index
         cancel - Set this to true to cancel the edit or return false from your handler.
     */
    onBeforeValueEdit: function(o) {
        if (o.field != 'value') {
            o.cancel = true;
        }

        else {
            var colModel = o.grid.getColumnModel(),
                type = o.record.get('type');

            if (o.record.get('source') == 'FILE') {
                // excluded by admin controller
            }
            o.record.beginEdit();

            if (o.record.get('source') == 'DEFAULT') {
                var def = o.record.get('default');
                o.value = String(def).match(/^[{\[]]/) ? def : Ext.encode(def);
            }

            o.record.set('value', Ext.decode(o.value));

            colModel.config[o.column].setEditor(
                Tine.Admin.config.FieldManager.create(o.record, {
                    app: this.configApp,
                    configRecord: o.record,
                    expandOnFocus: true
                })
            );
        }
    },

    /**
     * @param o
         grid - This grid
         record - The record being edited
         field - The field name being edited
         value - The value being set
         originalValue - The original value for the field, before the edit.
         row - The grid row index
         column - The grid column index
     */
    onAfterValuerEdit: function(o) {
        if (o.field == 'value') {
            o.value = Ext.encode(o.value);

            var def = o.record.get('default');
            def = String(def).match(/^[{\[]]/) ? def : Ext.encode(def);

            if (o.value == def) {
                o.record.cancelEdit();

                if (o.record.get('source') != 'DEFAULT') {
                    this.deleteRecords(this.grid.getSelectionModel(), [o.record]);
                }

                return;
            } else {
                if (o.record.get('source') == 'DEFAULT') {
                    o.record.set('source', '');
                }

                o.record.set('value', '');
                o.record.set('value', o.value);
            }

            if (o.record.get('id').match(/^virtual-/)) {
                o.record.set('id', '');
            }

            o.record.endEdit();

        }
    },

    initStore: function() {
        this.supr().initStore.call(this);

        this.store.on('beforeload', this.onStoreBeforeload, this);
    },

    onStoreBeforeload: function(store, options) {
        this.supr().onStoreBeforeload.call(this, store, options);
        options.params.filter.push({'field': 'application_id', 'operator': 'equals', 'value': this.configApp.id})
    },

    /**
     * called when the store gets updated, e.g. from editgrid
     *
     * @param {Ext.data.store} store
     * @param {Tine.Tinebase.data.Record} record
     * @param {String} operation
     */
    onStoreUpdate: function(store, record, operation) {
        this.supr().onStoreUpdate.call(this, store, record, operation);

        switch (operation) {
            case Ext.data.Record.EDIT:
                // do/check registry reload
                // TODO do this in parent window?
                Tine.Tinebase.common.confirmApplicationRestart(true);
                break;
        }
    },

    valueRenderer: function(value, metaData, record, rowIndex, colIndex, store) {
        if (record.get('source') == 'DEFAULT') {
            value = Ext.encode(record.get('default'));
        }

        switch (record.get('type')) {
            case 'bool':
                value = Tine.Tinebase.common.booleanRenderer(value);
                break;
            case 'keyField':
                value = Ext.decode(value);
                Ext.each(record.get('options')['records'], function(record) {
                    if (record.id == value) {
                        value = this.configApp.i18n._hidden(record.value);
                    }
                }, this);
                break;
            case 'keyFieldConfig':
                value = '...';
                break;
            default:
                break;
        }

        if (record.get('source') == 'DEFAULT') {
            return String.format(this.app.i18n._('Default ({0})'), value);
        }

        return value;
    }
});



/***/ }),

/***/ 327:
/***/ (function(module, exports) {

/*
 * Tine 2.0
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * @copyright   Copyright (c) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Admin');

Tine.Admin.QuotaUsage = Ext.extend(Ext.ux.tree.TreeGrid, {
    enableDD: false,
    border: false,

    initComponent: function() {
        var _ = window.lodash,
            comp = this;

        this.app = Tine.Tinebase.appMgr.get('Admin');

        this.loader = {
            directFn: Tine.Admin.searchQuotaNodes,
            getParams : function(node, callback, scope) {
                var path = node.getPath('name').replace(comp.getRootNode().getPath(), '/').replace(/\/+/, '/'),
                    filter = [{field: 'path', operator: 'equals', value: path}];

                if (path == '/' && comp.buttonRefreshData) {
                    comp.buttonRefreshData.disable();
                }

                return [filter];
            },
            processResponse: function(response, node, callback, scope) {
                if (comp.buttonRefreshData) {
                    comp.buttonRefreshData.enable();
                }
                response.responseData = response.responseText.results;
                
                return Ext.ux.tree.TreeGridLoader.prototype.processResponse.apply(this, arguments);
            },
            createNode: function(attr) {
                var app = Tine.Tinebase.appMgr.getById(attr.name);

                attr.i18n_name = app ? app.getTitle() : attr.name;

                return Ext.ux.tree.TreeGridLoader.prototype.createNode.apply(this, arguments);
            }
        };

        this.columns = [{
            id: 'i18n_name',
            header: this.app.i18n._("Name"),
            width: 400,
            sortable: true,
            dataIndex: 'i18n_name'
        }, {
            id: 'size',
            header: this.app.i18n._("Size"),
            width: 60,
            sortable: true,
            dataIndex: 'size',
            tpl: new Ext.XTemplate('{size:this.byteRenderer}', {
                byteRenderer: Tine.Tinebase.common.byteRenderer.createDelegate(this, [2, undefined], 3)
            })
        }];

        if (Tine.Tinebase.configManager.get('filesystem.modLogActive', 'Tinebase')) {
            this.columns.push({
                id: 'revision_size',
                header: this.app.i18n._("Revision Size"),
                tooltip: this.app.i18n._("Total size of all available revisions"),
                width: 60,
                sortable: true,
                dataIndex: 'revision_size',
                tpl: new Ext.XTemplate('{revision_size:this.byteRenderer}', {
                    byteRenderer: Tine.Tinebase.common.byteRenderer.createDelegate(this, [2, undefined], 3)
                })
            });
        }

        this.tbar = [{
            ref: '../buttonRefreshData',
            tooltip: Ext.PagingToolbar.prototype.refreshText,
            iconCls: "x-tbar-loading",
            handler: this.onButtonRefreshData,
            scope: this
        }];

        this.on('beforecollapsenode', this.onBeforeCollapse, this);

        this.supr().initComponent.apply(this, arguments);
    },

    /**
     * require reload when node is collapsed
     */
    onBeforeCollapse: function(node) {
        node.removeAll();
        node.loaded = false;
    },

    onButtonRefreshData: function() {
        this.getRootNode().reload();
    }
});

Tine.Admin.registerItem({
    // _('Quota Usage')
    text: 'Quota Usage',
    iconCls: 'admin-node-quota-usage',
    pos: 750,
    viewRight: 'view_quota_usage',
    panel: Tine.Admin.QuotaUsage
});

/***/ }),

/***/ 328:
/***/ (function(module, exports, __webpack_require__) {

// style-loader: Adds some css to the DOM by adding a <style> tag

// load the styles
var content = __webpack_require__(329);
if(typeof content === 'string') content = [[module.i, content, '']];
// Prepare cssTransformation
var transform;

var options = {"hmr":true}
options.transform = transform
// add the styles to the DOM
var update = __webpack_require__(1)(content, options);
if(content.locals) module.exports = content.locals;
// Hot Module Replacement
if(false) {
	// When the styles change, update the <style> tags
	if(!content.locals) {
		module.hot.accept("!!../../Tinebase/js/node_modules/css-loader/index.js!./Admin.css", function() {
			var newContent = require("!!../../Tinebase/js/node_modules/css-loader/index.js!./Admin.css");
			if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
			update(newContent);
		});
	}
	// When the module is disposed, remove the <style> tags
	module.hot.dispose(function() { update(); });
}

/***/ }),

/***/ 329:
/***/ (function(module, exports, __webpack_require__) {

exports = module.exports = __webpack_require__(0)(undefined);
// imports


// module
exports.push([module.i, ".action_settings {\n    background-image:url(" + __webpack_require__(13) + ") !important;\n}\n\n.action_permissions {\n    background-image:url(" + __webpack_require__(55) + ") !important;\n}\n\n.action_addGroup {\n    background-image:url(" + __webpack_require__(56) + ") !important;\n}\n\n.action_password {\n    background-image:url(" + __webpack_require__(55) + ") !important;\n}\n\n.AdminIconCls {\n    background-image:url(" + __webpack_require__(13) + ") !important;\n}\n\n.admin-node-accesslog {\n    background-image:url(" + __webpack_require__(330) + ") !important;\n}\n\n.admin-node-computers {\n    background-image:url(" + __webpack_require__(331) + ") !important;\n}\n\n.admin-node-server-info {\n    background-image:url(" + __webpack_require__(332) + ") !important;\n}\n\n.admin-node-applications {\n    background-image:url(" + __webpack_require__(333) + ") !important;\n}\n\n.admin-node-containers {\n    background-image:url(" + __webpack_require__(17) + ") !important;\n}\n\n.admin-action-add-container {\n    background-image:url(" + __webpack_require__(57) + ") !important;\n}\n\n.admin-node-customfields {\n    background-image:url(" + __webpack_require__(334) + ") !important;\n}\n\n.admin-action-add-customfield {\n    background-image:url(" + __webpack_require__(56) + ") !important;\n}\n\n.admin-node-customfields-store {\n    background-image:url(" + __webpack_require__(85) + ") !important;\n}\n\n.admin-node-quota-usage {\n    background-image:url(" + __webpack_require__(335) + ") !important;\n}\n\n.x-tree-node-collapsed .x-tree-node-icon.x-tree-node-leaf-checkbox, \n.x-tree-node-expanded .x-tree-node-icon.x-tree-node-leaf-checkbox, \n.x-tree-node-leaf .x-tree-node-icon.x-tree-node-leaf-checkbox ,\n.x-tree-node-leaf-checkbox {\n    width:0px;\n}\n", ""]);

// exports


/***/ }),

/***/ 330:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cstyle type='text/css'%3E .st0%7Bfill:%23FFFFFF;%7D .st1%7Bfont-family:'RobotoCondensed-Bold';%7D .st2%7Bfont-size:10.6404px;%7D .st3%7Bfill:none;%7D %3C/style%3E %3Cpath d='M32.2,16.1h-0.7v-3.3c0,0,0,0,0-0.1c0-0.1,0-0.3-0.1-0.4l-5.5-6.2c0,0,0,0,0,0c0,0-0.1-0.1-0.1-0.1c0,0,0,0,0,0 c0,0-0.1,0-0.1,0c0,0,0,0,0,0c0,0-0.1,0-0.1,0H12.1C11.5,6,11,6.5,11,7.1v9h-0.7c-0.9,0-1.6,0.7-1.6,1.6V26c0,0.9,0.7,1.6,1.6,1.6 H11v5.7c0,0.6,0.5,1.1,1.1,1.1h18.3c0.6,0,1.1-0.5,1.1-1.1v-5.7h0.7c0.9,0,1.6-0.7,1.6-1.6v-8.3C33.8,16.8,33.1,16.1,32.2,16.1 L32.2,16.1z M12.1,7.1H25v5.7c0,0.3,0.2,0.6,0.6,0.6h4.9v2.8H12.1V7.1z M30.4,32.9H12.1v-5.4h18.3V32.9z M28.5,25.3'/%3E %3Ctext transform='matrix(0.8458 0 0 1 9.5805 25.2407)' class='st0 st1 st2'%3EEXCEL%3C/text%3E %3Cpath d='M32.2,16.1h-0.7v-3.3c0,0,0,0,0-0.1c0-0.1,0-0.3-0.1-0.4l-5.5-6.2c0,0,0,0,0,0c0,0-0.1-0.1-0.1-0.1c0,0,0,0,0,0 c0,0-0.1,0-0.1,0c0,0,0,0,0,0c0,0-0.1,0-0.1,0H12.1C11.5,6,11,6.5,11,7.1v9h-0.7c-0.9,0-1.6,0.7-1.6,1.6V26c0,0.9,0.7,1.6,1.6,1.6 H11v5.7c0,0.6,0.5,1.1,1.1,1.1h18.3c0.6,0,1.1-0.5,1.1-1.1v-5.7h0.7c0.9,0,1.6-0.7,1.6-1.6v-8.3C33.8,16.8,33.1,16.1,32.2,16.1 L32.2,16.1z M12.1,7.1H25v5.7c0,0.3,0.2,0.6,0.6,0.6h4.9v2.8H12.1V7.1z M30.4,32.9H12.1v-5.4h18.3V32.9z M28.5,25.3'/%3E %3Crect x='8.7' y='17.7' class='st3' width='25.1' height='9.2'/%3E %3Ctext transform='matrix(0.8458 0 0 1 13.7582 25.708)' class='st0 st1 st2'%3ELOG%3C/text%3E %3C/svg%3E\""

/***/ }),

/***/ 331:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M35,6.9H9.2C7.4,6.9,6,8.3,6,10.1V14c0,1.8,1.4,3.2,3.2,3.2H35c1.8,0,3.2-1.4,3.2-3.2v-3.8C38.2,8.3,36.7,6.9,35,6.9z M35.4,13.4c0,0.6-0.5,1-1,1H9.8c-0.6,0-1-0.5-1-1v-2.7c0-0.6,0.5-1,1-1h24.5c0.6,0,1,0.5,1,1V13.4z M35,18.8H9.2 C7.4,18.8,6,20.2,6,22v3.8c0,1.8,1.4,3.2,3.2,3.2H35c1.8,0,3.2-1.4,3.2-3.2V22C38.2,20.2,36.7,18.8,35,18.8z M35.4,25.3 c0,0.6-0.5,1-1,1H9.8c-0.6,0-1-0.5-1-1v-2.7c0-0.6,0.5-1,1-1h24.5c0.6,0,1,0.5,1,1V25.3z M12,12.1c0,0.5-0.4,1-1,1s-1-0.4-1-1 s0.4-1,1-1S12,11.5,12,12.1z M12,24c0,0.5-0.4,1-1,1s-1-0.4-1-1c0-0.5,0.4-1,1-1S12,23.4,12,24z M38.2,32.9c0,0.6-0.5,1.1-1.1,1.1 H25.8c-0.4,0.8-1.2,1.4-2.2,1.4h-1.7c-1,0-1.8-0.6-2.2-1.4H7.1C6.5,34,6,33.5,6,32.9s0.5-1.1,1.1-1.1h12.6c0.4-0.8,1.2-1.4,2.2-1.4 h1.7c1,0,1.8,0.6,2.2,1.4h11.3C37.7,31.8,38.2,32.3,38.2,32.9z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 332:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M4.1,24.1c0-0.5,0.4-1,1-1s1,0.4,1,1c0,0.5-0.4,1-1,1S4.1,24.6,4.1,24.1z M24.3,17.3H3.2c-1.8,0-3.2-1.4-3.2-3.2v-3.8 C0,8.4,1.4,7,3.2,7H29c1.8,0,3.2,1.4,3.2,3.2v3.6c-1.9,0.1-3.8,0.6-5.4,1.6C25.8,15.9,25,16.5,24.3,17.3z M3.8,14.5h24.5 c0.6,0,1-0.5,1-1v-2.7c0-0.6-0.5-1-1-1H3.8c-0.6,0-1,0.5-1,1v2.7C2.8,14,3.3,14.5,3.8,14.5z M5,11.2c-0.5,0-1,0.4-1,1s0.4,1,1,1 s1-0.4,1-1S5.6,11.2,5,11.2z M22.7,31.9h-2.9c-0.4-0.8-1.2-1.4-2.2-1.4h-1.7c-1,0-1.8,0.6-2.2,1.4H1.1C0.5,31.9,0,32.4,0,33 s0.5,1.1,1.1,1.1h12.6c0.4,0.8,1.2,1.4,2.2,1.4h1.7c1,0,1.8-0.6,2.2-1.4h4.7C23.8,33.4,23.2,32.7,22.7,31.9z M3.8,26.4 c-0.6,0-1-0.5-1-1v-2.7c0-0.6,0.5-1,1-1h17.7c0.2-0.7,0.5-1.3,0.9-2c0.2-0.3,0.3-0.5,0.5-0.8H3.2c-1.8,0-3.2,1.4-3.2,3.2V26 c0,1.8,1.4,3.2,3.2,3.2h18.2c-0.3-0.9-0.4-1.8-0.5-2.8H3.8z M41.2,20.7c-0.9-1.5-2.1-2.7-3.6-3.6s-3.2-1.3-4.9-1.3s-3.4,0.4-4.9,1.3 s-2.7,2.1-3.6,3.6s-1.3,3.2-1.3,4.9s0.4,3.4,1.3,4.9s2.1,2.7,3.6,3.6s3.2,1.3,4.9,1.3s3.4-0.4,4.9-1.3s2.7-2.1,3.6-3.6 s1.3-3.2,1.3-4.9S42.1,22.2,41.2,20.7z M39.4,29.5c-0.7,1.2-1.6,2.1-2.8,2.8c-1.2,0.7-2.5,1-3.9,1s-2.7-0.3-3.9-1 c-1.2-0.7-2.1-1.6-2.8-2.8c-0.7-1.2-1-2.5-1-3.9s0.3-2.7,1-3.9c0.7-1.2,1.6-2.1,2.8-2.8c1.2-0.7,2.5-1,3.9-1s2.7,0.3,3.9,1 c1.2,0.7,2.1,1.6,2.8,2.8c0.7,1.2,1,2.5,1,3.9S40.1,28.3,39.4,29.5z M35.9,28.8C36,28.9,36,29,36,29.2v1.1c0,0.1,0,0.3-0.1,0.4 c-0.1,0.1-0.2,0.2-0.3,0.2h-5c-0.1,0-0.2-0.1-0.3-0.2c-0.1-0.1-0.1-0.2-0.1-0.4v-1.1c0-0.1,0-0.3,0.1-0.4c0.1-0.1,0.2-0.2,0.3-0.2 h1.6v-3.2h-1.6c-0.1,0-0.2-0.1-0.3-0.2C30.1,25.2,30,25.1,30,25v-1.1c0-0.1,0-0.3,0.1-0.4c0.1-0.1,0.2-0.2,0.3-0.2h3.4 c0.1,0,0.2,0.1,0.3,0.2c0.1,0.1,0.1,0.2,0.1,0.4v4.7h1.2C35.7,28.6,35.8,28.7,35.9,28.8z M32.1,20.2c0-0.1,0-0.3,0.1-0.4 s0.2-0.2,0.3-0.2h1.3c0.1,0,0.2,0.1,0.3,0.2c0.1,0.1,0.1,0.2,0.1,0.4v1.1c0,0.1,0,0.3-0.1,0.4c-0.1,0.1-0.2,0.2-0.3,0.2h-1.3 c-0.1,0-0.2-0.1-0.3-0.2s-0.1-0.2-0.1-0.4V20.2z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 333:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M31.8,22h2.7c0.5,0,0.8-0.4,0.8-0.8v-8c0-0.5-0.4-0.8-0.8-0.8h-7.2v-1.8c0-1.9-1.6-3.5-3.5-3.5s-3.5,1.6-3.5,3.5v1.8h-7.2 c-0.5,0-0.8,0.4-0.8,0.8v7.2h-1.8c-1.9,0-3.5,1.6-3.5,3.5s1.6,3.5,3.5,3.5h1.8v7.2c0,0.5,0.4,0.8,0.8,0.8h8c0.5,0,0.8-0.4,0.8-0.8 v-2.7c0-1,0.8-1.8,1.8-1.8s1.8,0.8,1.8,1.8v2.7c0,0.5,0.4,0.8,0.8,0.8h8c0.5,0,0.8-0.4,0.8-0.8v-8c0-0.5-0.4-0.8-0.8-0.8h-2.7 c-1,0-1.8-0.8-1.8-1.8S30.8,22,31.8,22z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 334:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M14.6,13.9v9.1h2V25h-2v3.4c0,1,1.9,1,2,1v1.9c-1.1,0-2.2-0.3-2.9-0.9c-0.8,0.6-1.9,0.9-2.9,0.9v-1.9c0.1,0,2,0,2-1V25h-2 v-1.9h2v-9.1c0-1-1.9-1-2-1V11c1.1,0,2.2,0.3,2.9,0.9c0.8-0.6,1.9-0.9,2.9-0.9v1.9C16.5,12.9,14.6,12.9,14.6,13.9L14.6,13.9z M14.6,13.9 M38,7H3.2C2.5,7,2,7.5,2,8.2v25.9c0,0.7,0.5,1.2,1.2,1.2H38c0.7,0,1.2-0.5,1.2-1.2V8.2C39.3,7.5,38.7,7,38,7z M4.4,32.9 V9.4h32.4v23.5H4.4z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 335:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cg%3E %3Cpath d='M37.7,23.1L33.3,9.6c-0.3-0.8-0.7-1.4-1.4-1.9C31.2,7.2,30.5,7,29.7,7H12.3c-0.8,0-1.6,0.2-2.2,0.7C9.4,8.2,9,8.9,8.7,9.6 L4.4,23.1C4.1,23.8,4,24.3,4,24.7v7.1c0,1,0.3,1.8,1,2.5c0.7,0.7,1.5,1,2.5,1h26.9c1,0,1.8-0.3,2.5-1c0.7-0.7,1-1.5,1-2.5v-7.1 C38,24.3,37.9,23.8,37.7,23.1L37.7,23.1z M11.4,10.5c0.1-0.2,0.2-0.4,0.4-0.5c0.2-0.1,0.4-0.2,0.6-0.2h17.3c0.2,0,0.4,0.1,0.6,0.2 c0.2,0.1,0.3,0.3,0.4,0.5l3.5,10.7H7.9L11.4,10.5z M35.2,31.8c0,0.2-0.1,0.4-0.2,0.5c-0.1,0.1-0.3,0.2-0.5,0.2H7.5 c-0.2,0-0.4-0.1-0.5-0.2c-0.1-0.1-0.2-0.3-0.2-0.5v-7.1c0-0.2,0.1-0.4,0.2-0.5C7.2,24.1,7.4,24,7.5,24h26.9c0.2,0,0.4,0.1,0.5,0.2 c0.1,0.1,0.2,0.3,0.2,0.5V31.8z M35.2,31.8'/%3E %3Cpath d='M25.3,26.5c-0.5,0-0.9,0.2-1.3,0.5c-0.3,0.3-0.5,0.8-0.5,1.3c0,0.5,0.2,0.9,0.5,1.3c0.3,0.3,0.8,0.5,1.3,0.5 c0.5,0,0.9-0.2,1.3-0.5c0.3-0.3,0.5-0.8,0.5-1.3c0-0.5-0.2-0.9-0.5-1.3C26.2,26.7,25.7,26.5,25.3,26.5L25.3,26.5z M25.3,26.5'/%3E %3Cpath d='M30.9,26.5c-0.5,0-0.9,0.2-1.3,0.5c-0.3,0.3-0.5,0.8-0.5,1.3c0,0.5,0.2,0.9,0.5,1.3c0.3,0.3,0.8,0.5,1.3,0.5 c0.5,0,0.9-0.2,1.3-0.5c0.3-0.3,0.5-0.8,0.5-1.3c0-0.5-0.2-0.9-0.5-1.3C31.8,26.7,31.4,26.5,30.9,26.5L30.9,26.5z M30.9,26.5'/%3E %3C/g%3E %3C/svg%3E\""

/***/ }),

/***/ 55:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M34.7,30.4c0-0.2-0.1-0.3-0.2-0.5L23.3,18.8c0.4-1,0.7-2.2,0.7-3.3c0-2.3-0.9-4.4-2.5-6c-1.6-1.6-3.7-2.5-6-2.5 c-2.3,0-4.4,0.9-6,2.5c-3.3,3.3-3.3,8.7,0,12c1.6,1.6,3.7,2.5,6,2.5c1.2,0,2.3-0.2,3.3-0.7l3.7,3.7c0.2,0.2,0.4,0.2,0.6,0.2l2-0.1 l-0.1,2c0,0.2,0.1,0.4,0.2,0.6c0.1,0.2,0.4,0.2,0.6,0.2l2-0.1l-0.1,2c0,0.2,0.1,0.4,0.2,0.6c0.2,0.2,0.3,0.2,0.6,0.2l2-0.1l-0.1,2 c0,0.2,0.1,0.4,0.2,0.6c0.1,0.1,0.3,0.2,0.5,0.2c0,0,0.1,0,0.1,0l3.1-0.3c0.4,0,0.7-0.4,0.7-0.8L34.7,30.4z M14.4,14.5 c-0.9,0.9-2.5,0.9-3.4,0c-0.9-0.9-0.9-2.5,0-3.4c0.9-0.9,2.5-0.9,3.4,0C15.4,12,15.4,13.5,14.4,14.5L14.4,14.5z M32,30.7 c-0.1,0.1-0.3,0.2-0.4,0.2c-0.1,0-0.3-0.1-0.4-0.2l-9.5-9.5c0.3-0.3,0.5-0.6,0.7-0.9l9.6,9.6C32.3,30.1,32.3,30.5,32,30.7L32,30.7z M32,30.7'/%3E %3C/svg%3E\""

/***/ }),

/***/ 56:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M22.2,38h-2.4c-0.4,0-0.6-0.1-0.9-0.3c-0.2-0.2-0.3-0.5-0.3-0.9V23.4H5.2c-0.4,0-0.6-0.1-0.9-0.3C4.1,22.8,4,22.6,4,22.2 v-2.4c0-0.4,0.1-0.6,0.3-0.9c0.2-0.2,0.5-0.3,0.9-0.3h13.3V5.2c0-0.4,0.1-0.6,0.3-0.9C19.1,4.1,19.4,4,19.8,4h2.4 c0.4,0,0.6,0.1,0.9,0.3c0.2,0.2,0.3,0.5,0.3,0.9v13.3h13.3c0.4,0,0.6,0.1,0.9,0.3c0.2,0.2,0.3,0.5,0.3,0.9v2.4 c0,0.4-0.1,0.6-0.3,0.9s-0.5,0.3-0.9,0.3H23.4v13.3c0,0.4-0.1,0.6-0.3,0.9S22.6,38,22.2,38z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 57:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath id='Ordner_anlegen' d='M34.9,30.1V16.4c0-0.5-0.2-1-0.5-1.3s-0.8-0.5-1.3-0.5H19.3c-0.5,0-1-0.2-1.3-0.5 c-0.4-0.4-0.5-0.8-0.5-1.3v-1.2c0-0.5-0.2-1-0.5-1.3c-0.4-0.4-0.8-0.5-1.3-0.5H9.4c-0.5,0-1,0.2-1.3,0.5c-0.4,0.4-0.5,0.8-0.5,1.3 v18.7c0,0.5,0.2,1,0.5,1.3C8.4,31.8,8.8,32,9.4,32H33c0.5,0,1-0.2,1.3-0.5S34.9,30.6,34.9,30.1z M37.4,16.4v13.7 c0,1.2-0.4,2.2-1.3,3.1c-0.9,0.9-1.9,1.3-3.1,1.3H9.4c-1.2,0-2.2-0.4-3.1-1.3C5.4,32.3,5,31.3,5,30.1V11.4c0-1.2,0.4-2.2,1.3-3.1 S8.2,7,9.4,7h6.2c1.2,0,2.2,0.4,3.1,1.3c0.9,0.9,1.3,1.9,1.3,3.1V12H33c1.2,0,2.2,0.4,3.1,1.3C37,14.1,37.4,15.2,37.4,16.4z'/%3E %3Cpath d='M21.7,29.4h-1c-0.1,0-0.3,0-0.3-0.1c-0.1-0.1-0.1-0.2-0.1-0.3v-5.3H15c-0.1,0-0.3,0-0.3-0.1c-0.1-0.1-0.1-0.2-0.1-0.3v-1 c0-0.1,0-0.3,0.1-0.3c0.1-0.1,0.2-0.1,0.3-0.1h5.3v-5.3c0-0.1,0-0.3,0.1-0.3c0.1-0.1,0.2-0.1,0.3-0.1h1c0.1,0,0.3,0,0.3,0.1 c0.1,0.1,0.1,0.2,0.1,0.3v5.3h5.3c0.1,0,0.3,0,0.3,0.1c0.1,0.1,0.1,0.2,0.1,0.3v1c0,0.1,0,0.3-0.1,0.3c-0.1,0.1-0.2,0.1-0.3,0.1 h-5.3V29c0,0.1,0,0.3-0.1,0.3C21.9,29.4,21.8,29.4,21.7,29.4z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 85:
/***/ (function(module, exports) {

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E %3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 42.5 42.5' style='enable-background:new 0 0 42.5 42.5;' xml:space='preserve'%3E %3Cpath d='M21.6,34.3c3,0,5.3-0.2,8.4-1c2.8-0.7,4.8-1.6,6.2-3.2v3.1c0,0.9-0.7,1.7-2,2.4s-3.1,1.3-5.3,1.8S24.2,38,21.6,38 s-5.1-0.2-7.3-0.7s-4-1-5.3-1.8S7,34,7,33.1v-3.3c0.7,1.2,2.3,2.4,6,3.5C15.7,34,18.6,34.3,21.6,34.3z M21.6,4 c2.6,0,5.1,0.2,7.3,0.7c2.2,0.4,4,1,5.3,1.8s2,1.6,2,2.4v2.4c0,0.9-0.7,1.7-2,2.4c-1.3,0.7-3.1,1.3-5.3,1.8s-4.7,0.7-7.3,0.7 s-5.1-0.2-7.3-0.7s-4-1-5.3-1.8c-1.3-0.7-2-1.6-2-2.4V8.9C7,8,7.7,7.2,9,6.4s3.1-1.3,5.3-1.8C16.5,4.2,18.9,4,21.6,4z M21.6,27 c3,0,5.3-0.2,8.4-1c2.8-0.7,4.8-1.6,6.2-3.2v3.1c0,0.9-0.7,1.7-2,2.4s-3.1,1.3-5.3,1.8c-2.2,0.4-4.7,0.7-7.3,0.7s-5.1-0.2-7.3-0.7 c-2.2-0.4-4-1-5.3-1.8s-2-1.6-2-2.4v-3.3c0.7,1.2,2.3,2.4,6,3.5C15.7,26.7,18.6,27,21.6,27z M21.6,19.6c3,0,5.3-0.2,8.4-1 c2.8-0.7,4.8-1.6,6.2-3.2v3.1c0,0.9-0.7,1.7-2,2.4s-3.1,1.3-5.3,1.8c-2.2,0.4-4.7,0.7-7.3,0.7s-5.1-0.2-7.3-0.7 c-2.2-0.4-4-1-5.3-1.8s-2-1.6-2-2.4v-3.3c0.7,1.2,2.3,2.4,6,3.5C15.7,19.3,18.6,19.6,21.6,19.6z'/%3E %3C/svg%3E\""

/***/ })

/******/ });
});