(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 = 629);
/******/ })
/************************************************************************/
/******/ ({

/***/ 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);
}


/***/ }),

/***/ 105:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath id='Icon_Passwort' d='M12.5,19.5h16.7v-4.4c0-2.4-0.8-4.4-2.5-6.1c-1.7-1.7-3.3-2.5-5.7-2.5S16.7,7.3,15,9s-2.5,3.7-2.5,6.1 V19.5z M34.8,21.8v13.9c0,0.6-0.2,1.2-0.7,1.6c-0.5,0.5-1,0.7-1.6,0.7H9.3c-0.6,0-1.2-0.2-1.6-0.7c-0.5-0.5-0.7-1-0.7-1.6V21.8 c0-0.6,0.2-1.2,0.7-1.6c0.5-0.5,1-0.7,1.6-0.7h0.8v-4.6c0-3,1.1-5.5,3.2-7.6S17.9,4,20.9,4s5.5,1.1,7.6,3.2s3.2,4.7,3.2,7.6v4.6h0.8 c0.6,0,1.2,0.2,1.6,0.7C34.6,20.6,34.8,21.1,34.8,21.8z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 106:
/***/ (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' width='42.5' height='42.5'%3E %3Cg%3E %3Cpath d='M12.5,19.5v-4.4c0-2.4,0.8-4.4,2.5-6.1c1.7-1.7,3.5-2.5,5.9-2.5s4,0.8,5.7,2.5c1.4,1.4,2.2,3,2.5,4.9 c0.1,0.8,2.7,0.4,2.5-0.6c-0.3-2.3-1.3-4.3-3.1-6.1C26.4,5.1,23.9,4,20.9,4s-5.5,1.1-7.6,3.2s-3.2,4.7-3.2,7.6v4.6H9.3 c-0.6,0-1.2,0.2-1.6,0.7c-0.5,0.5-0.7,1-0.7,1.6v13.9c0,0.6,0.2,1.2,0.7,1.6s1,0.7,1.6,0.7h23.2c0.6,0,1.2-0.2,1.6-0.7 c0.5-0.5,0.7-1,0.7-1.6V21.8c0-0.6-0.2-1.2-0.7-1.6c-0.5-0.5-1-0.7-1.6-0.7L12.5,19.5z'/%3E %3C/g%3E %3C/svg%3E\""

/***/ }),

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

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Martin Jatho <m.jatho@metaways.de>
 * @copyright   Copyright (c) 2007-2012 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

__webpack_require__(178);

Tine.Filemanager.nodeContextMenu = {
    actionMgr: Tine.Filemanager.nodeActionsMgr,

    /**
     * on pause
     * @param {} button
     * @param {} event
     */
    onPause: function (button, event) {

        var grid = this.scope;
        var gridStore = grid.store;
        gridStore.suspendEvents();
        var selectedRows = grid.selectionModel.getSelections();
        for(var i=0; i < selectedRows.length; i++) {
            var fileRecord = selectedRows[i];
            if(fileRecord.fileRecord) {
                fileRecord = fileRecord.fileRecord;
            }
            var upload = Tine.Tinebase.uploadManager.getUpload(fileRecord.get('uploadKey'));
            if (upload) {
                upload.setPaused(true);
            }
        }
        gridStore.resumeEvents();
        grid.actionUpdater.updateActions(gridStore);
        this.scope.selectionModel.deselectRange(0, this.scope.selectionModel.getCount());
    },

    
    /**
     * on resume
     * @param {} button
     * @param {} event
     */
    onResume: function (button, event) {
        
        var grid = this.scope;
        var gridStore = grid.store;
        gridStore.suspendEvents();
        var selectedRows = grid.selectionModel.getSelections();
        for(var i=0; i < selectedRows.length; i++) {
            var fileRecord = selectedRows[i];
            if(fileRecord.fileRecord) {
                fileRecord = fileRecord.fileRecord;
            }
            var upload = Tine.Tinebase.uploadManager.getUpload(fileRecord.get('uploadKey'));
            upload.resumeUpload();
        }
        gridStore.resumeEvents();
        grid.actionUpdater.updateActions(gridStore);
        this.scope.selectionModel.deselectRange(0, this.scope.selectionModel.getCount());

    },
    
    /**
     * checks whether resume button shuold be enabled or disabled
     * 
     * @param action
     * @param grants
     * @param records
     */
    isResumeEnabled: function(action, grants, records) {
        
        for(var i=0; i<records.length; i++) {
            
            var record = records[i];
            if(record.fileRecord) {
                record = record.fileRecord;
            }
            
            if(record.get('type') == 'folder') {
                action.hide();
                return;
            }
        }
       
        for(var i=0; i < records.length; i++) {
            
            var record = records[i];
            if(record.fileRecord) {
                record = record.fileRecord;
            }
            if(!record.get('status') || (record.get('type') != 'folder' &&  record.get('status') != 'uploading' 
                    &&  record.get('status') != 'paused' && record.get('status') != 'pending')) {
                action.hide();
                return;
            }
        }
        
        action.show();
        
        for(var i=0; i < records.length; i++) {
            
            var record = records[i];
            if(record.fileRecord) {
                record = record.fileRecord;
            }
            
            if(record.get('status')) {
                action.setDisabled(false);
            }
            else {
                action.setDisabled(true);
            }
            if(record.get('status') && record.get('status') != 'paused') {
                action.setDisabled(true);
            }
            
        }   
    },
    
    /**
     * checks whether pause button shuold be enabled or disabled
     * 
     * @param action
     * @param grants
     * @param records
     */
    isPauseEnabled: function(action, grants, records) {
        
        for(var i=0; i<records.length; i++) {
            
            var record = records[i];
            if(record.fileRecord) {
                record = record.fileRecord;
            }
            
            if(record.get('type') === 'folder') {
                action.hide();
                return;
            }
        }
        
        for(var i=0; i < records.length; i++) {
            
            var record = records[i];
            if(record.fileRecord) {
                record = record.fileRecord;
            }
            
            if(!record.get('status') || (record.get('type ') != 'folder' && record.get('status') != 'paused'
                    &&  record.get('status') != 'uploading' && record.get('status') != 'pending')) {
                action.hide();
                return;
            }
        }
        
        action.show();
        
        for(var i=0; i < records.length; i++) {
            
            var record = records[i];
            if(record.fileRecord) {
                record = record.fileRecord;
            }
            
            if(record.get('status')) {
                action.setDisabled(false);
            }
            else {
                action.setDisabled(true);
            }
            if(record.get('status') && record.get('status') !=='uploading'){
                action.setDisabled(true);
            }
            
        }
    }
};

// extends Tine.widgets.tree.ContextMenu
Ext.applyIf(Tine.Filemanager.nodeContextMenu, Tine.widgets.tree.ContextMenu);


/***/ }),

/***/ 178:
/***/ (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) 2017-2019 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager.nodeActions');

/**
 * @singleton
 */
Tine.Filemanager.nodeActionsMgr = new (Ext.extend(Tine.widgets.ActionManager, {
    actionConfigs: Tine.Filemanager.nodeActions
}))();

// /**
//  * reload
//  */
// Tine.Filemanager.nodeActions.Reload = {
//     app: 'Filemanager',
//     text: 'Reload', // _('Reload'),
//     iconCls: 'x-tbar-loading',
//     handler: function() {
//         var record = this.initialConfig.selections[0];
//         // arg - does not trigger tree children reload!
//         Tine.Filemanager.fileRecordBackend.loadRecord(record);
//     }
// };

/**
 * create new folder, needs a single folder selection with addGrant
 */
Tine.Filemanager.nodeActions.CreateFolder = {
    app: 'Filemanager',
    requiredGrant: 'addGrant',
    allowMultiple: false,
    // actionType: 'add',
    text: 'Create Folder', // _('Create Folder')
    disabled: true,
    iconCls: 'action_create_folder',
    scope: this,
    handler: function() {
        var app = this.initialConfig.app,
            currentFolderNode = this.initialConfig.selections[0],
            nodeName = Tine.Filemanager.Model.Node.getContainerName();

        Ext.MessageBox.prompt(app.i18n._('New Folder'), app.i18n._('Please enter the name of the new folder:'), function(btn, text) {
            if(currentFolderNode && btn == 'ok') {
                if (! text) {
                    Ext.Msg.alert(String.format(app.i18n._('No {0} added'), nodeName), String.format(app.i18n._('You have to supply a {0} name!'), nodeName));
                    return;
                }

                var filename = currentFolderNode.get('path') + '/' + text;
                Tine.Filemanager.fileRecordBackend.createFolder(filename);
            }
        }, this);
    },
    actionUpdater: function(action, grants, records, isFilterSelect) {
        var enabled = !isFilterSelect
            && records && records.length == 1
            && records[0].get('type') == 'folder'
            && window.lodash.get(records, '[0].data.account_grants.addGrant', false);

        action.setDisabled(!enabled);
    }
};

/**
 * show native file select, upload files, create nodes
 * a single directory node with create grant has to be selected
 * for this action to be active
 */
// Tine.Filemanager.nodeActions.UploadFiles = {};

/**
 * single file or directory node with readGrant
 */
Tine.Filemanager.nodeActions.Edit = {
    app: 'Filemanager',
    requiredGrant: 'readGrant',
    allowMultiple: false,
    text: 'Edit Properties', // _('Edit Properties')
    iconCls: 'action_edit_file',
    disabled: true,
    // actionType: 'edit',
    scope: this,
    handler: function () {
        if(this.initialConfig.selections.length == 1) {
            Tine.Filemanager.NodeEditDialog.openWindow({record: this.initialConfig.selections[0]});
        }
    },
    actionUpdater: function(action, grants, records, isFilterSelect) {
        Tine.Filemanager.nodeActions.checkDisabled(action, grants, records, isFilterSelect);
    }
};

/**
 * single file or directory node with editGrant
 */
Tine.Filemanager.nodeActions.Rename = {
    app: 'Filemanager',
    requiredGrant: 'editGrant',
    allowMultiple: false,
    text: 'Rename', // _('Rename')
    iconCls: 'action_rename',
    disabled: true,
    // actionType: 'edit',
    scope: this,
    handler: function () {
        var _ = window.lodash,
            app = this.initialConfig.app,
            record = this.initialConfig.selections[0],
            nodeName = record.get('type') == 'folder' ?
                Tine.Filemanager.Model.Node.getContainerName() :
                Tine.Filemanager.Model.Node.getRecordName();

        Ext.MessageBox.show({
            title: String.format(i18n._('Rename {0}'), nodeName),
            msg: String.format(i18n._('Please enter the new name of the {0}:'), nodeName),
            buttons: Ext.MessageBox.OKCANCEL,
            value: record.get('name'),
            fn: function (btn, text) {
                if (btn == 'ok') {
                    if (!text) {
                        Ext.Msg.alert(String.format(i18n._('Not renamed {0}'), nodeName), String.format(i18n._('You have to supply a {0} name!'), nodeName));
                        return;
                    }

                    // @TODO validate filename
                    var targetPath = record.get('path').replace(new RegExp(_.escapeRegExp(record.get('name')) +'$'), text);
                    Tine.Filemanager.fileRecordBackend.copyNodes([record], targetPath, true);

                }
            },
            scope: this,
            prompt: true,
            icon: Ext.MessageBox.QUESTION
        });
    }
};

/**
 * single file or directory node with editGrant
 */
Tine.Filemanager.nodeActions.SystemLink = {
    app: 'Filemanager',
    requiredGrant: 'readGrant',
    allowMultiple: false,
    text: 'System Link', // _('System Link')
    iconCls: 'action_system_link',
    disabled: true,
    // actionType: 'edit',
    scope: this,
    handler: function () {
        var _ = window.lodash,
            app = this.initialConfig.app,
            record = this.initialConfig.selections[0];

        Ext.MessageBox.show({
            title: i18n._('System Link'),
            // minWidth:
            maxWidth: screen.availWidth,
            msg: '<b>' + app.i18n._('Use this link to share the entry with other system users') + ':</b><br>'
                    + record.getSystemLink(),
            buttons: Ext.MessageBox.OK,
            // value: record.getSystemLink(),
            // prompt: true,
            icon: Ext.MessageBox.INFO
        });
    },
    actionUpdater: function(action, grants, records, isFilterSelect) {
        Tine.Filemanager.nodeActions.checkDisabled(action, grants, records, isFilterSelect);
    }
};

/**
 * one or multiple nodes, all need deleteGrant
 */
Tine.Filemanager.nodeActions.Delete = {
    app: 'Filemanager',
    requiredGrant: 'deleteGrant',
    allowMultiple: true,
    text: 'Delete', // _('Delete')
    disabled: true,
    iconCls: 'action_delete',
    scope: this,
    handler: function (button, event) {
        var app = this.initialConfig.app,
            nodeName = '',
            nodes = this.initialConfig.selections;

        if (nodes && nodes.length) {
            for (var i = 0; i < nodes.length; i++) {
                var currNodeData = nodes[i].data;
                nodeName += Tine.Tinebase.EncodingHelper.encode(typeof currNodeData.name == 'object' ?
                    currNodeData.name.name :
                    currNodeData.name) + '<br />';
            }
        }

        this.conflictConfirmWin = Tine.widgets.dialog.FileListDialog.openWindow({
            modal: true,
            allowCancel: false,
            height: 180,
            width: 300,
            title: app.i18n._('Do you really want to delete the following files?'),
            text: nodeName,
            scope: this,
            handler: function (button) {
                if (nodes && button == 'yes') {
                    Tine.Filemanager.fileRecordBackend.deleteItems(nodes);
                }

                for (var i = 0; i < nodes.length; i++) {
                    var node = nodes[i];

                    if (node.fileRecord) {
                        var upload = Tine.Tinebase.uploadManager.getUpload(node.fileRecord.get('uploadKey'));
                        if (upload) {
                            upload.setPaused(true);
                            Tine.Tinebase.uploadManager.unregisterUpload(upload.id);
                        }
                    }

                }
            }
        });
    }
};

/**
 * one node with readGrant
 */
// Tine.Filemanager.nodeActions.Copy = {};

/**
 * one or multiple nodes with read, edit AND deleteGrant
 */
Tine.Filemanager.nodeActions.Move = {
    app: 'Filemanager',
    requiredGrant: 'editGrant',
    allowMultiple: true,
    text: 'Move', // _('Move')
    disabled: true,
    actionType: 'edit',
    scope: this,
    iconCls: 'action_move',
    handler: function() {
        var app = this.initialConfig.app,
            i18n = app.i18n,
            records = this.initialConfig.selections;

        var filePickerDialog = new Tine.Filemanager.FilePickerDialog({
            windowTitle: app.i18n._('Move Items'),
            singleSelect: true,
            constraint: 'folder'
        });

        filePickerDialog.on('apply', function(node) {
            Tine.Filemanager.fileRecordBackend.copyNodes(records, node, true);
        });

        filePickerDialog.openWindow();
    }
};

/**
 * one file node with download grant
 */
Tine.Filemanager.nodeActions.Download = {
    app: 'Filemanager',
    requiredGrant: 'downloadGrant',
    allowMultiple: false,
    actionType: 'download',
    text: 'Save locally', // _('Save locally')
    iconCls: 'action_filemanager_save_all',
    disabled: true,
    scope: this,
    init: function() {
        this.hidden = !Tine.Tinebase.configManager.get('downloadsAllowed');
    },
    handler: function() {
        Tine.Filemanager.downloadFile(this.initialConfig.selections[0]);
    },
    actionUpdater: function(action, grants, records, isFilterSelect) {

        var enabled = !isFilterSelect
            && records && records.length == 1
            && records[0].get('type') != 'folder'
            && window.lodash.get(records, '[0].data.account_grants.downloadGrant', false);

        action.setDisabled(!enabled);
    }
};

/**
 * one file node with readGrant
 */
Tine.Filemanager.nodeActions.Preview = {
    app: 'Filemanager',
    allowMultiple: false,
    requiredGrant: 'readGrant',
    text: 'Preview', // _('Preview')
    disabled: true,
    iconCls: 'action_preview',
    scope: this,
    handler: function () {
        var selections = this.initialConfig.selections;

        if (selections.length > 0) {
            var selection = selections[0];

            if (selection && selection.get('type') === 'file') {
                Tine.Filemanager.DocumentPreview.openWindow({
                    record: selection,
                    initialApp: this.initialConfig.initialApp || null,
                    sm: this.initialConfig.sm
                });
            }
        }
    },
    actionUpdater: function(action, grants, records, isFilterSelect) {
        Tine.Filemanager.nodeActions.checkDisabled(action, grants, records, isFilterSelect);
    }
};

/**
 * one node with publish grant
 */
Tine.Filemanager.nodeActions.Publish = {
    app: 'Filemanager',
    allowMultiple: false,
    text: 'Publish', // _('Publish')
    disabled: true,
    iconCls: 'action_publish',
    scope: this,
    handler: function() {
        var app = this.initialConfig.app,
            i18n = app.i18n,
            selections = this.initialConfig.selections;

        if (selections.length != 1) {
            return;
        }

        var passwordDialog = new Tine.Tinebase.widgets.dialog.PasswordDialog({
            allowEmptyPassword: true,
            locked: false,
            questionText: i18n._('Public download links can be password protected. If left blank anyone who knows the link can download the selected files.')
        });
        passwordDialog.openWindow();

        passwordDialog.on('apply', function (password) {
            var date = new Date();
            date.setDate(date.getDate() + 30);

            var record = new Tine.Filemanager.Model.DownloadLink({
                node_id: selections[0].id,
                expiry_time: date,
                password: password
            });

            Tine.Filemanager.downloadLinkRecordBackend.saveRecord(record, {
                success: function (record) {
                    Tine.Filemanager.FilePublishedDialog.openWindow({
                        title: selections[0].data.type == 'folder' ? app.i18n._('Folder has been published successfully') : app.i18n._('File has been published successfully'),
                        record: record,
                        password: password
                    });
                }, failure: Tine.Tinebase.ExceptionHandler.handleRequestException, scope: this
            });
        }, this);
    },
    actionUpdater: function(action, grants, records, isFilterSelect) {

        var enabled = !isFilterSelect
            && records && records.length == 1
            && window.lodash.get(records, '[0].data.account_grants.publishGrant', false);

        Tine.Filemanager.nodeActions.checkDisabled(action, grants, records, isFilterSelect, enabled);
    }
};

/**
 *
 * helper for disabled field
 * @param action
 * @param grants
 * @param records
 * @param isFilterSelect
 * @returns {*}
 */
Tine.Filemanager.nodeActions.checkDisabled = function(action, grants, records, isFilterSelect, enabled = true)
{
    // run default updater
    Tine.widgets.ActionUpdater.prototype.defaultUpdater(action, grants, records, isFilterSelect);

    var _ = window.lodash,
        disabled = _.isFunction(action.isDisabled) ? action.isDisabled() : action.disabled;

    // if enabled check for not accessible node and disable
    if (! disabled || !enabled) {

        action.setDisabled(window.lodash.reduce(records, function(disabled, record) {
            var isVirtual = _.isFunction(record.isVirtual) ? record.isVirtual() : false;
            return disabled || isVirtual || record.get('is_quarantined') == '1';
        }, false));
    }
};

/**
 * one or multiple file nodes currently uploaded
 */
Tine.Filemanager.nodeActions.PauseUploadAction = {};

/**
 * one or multiple file nodes currently upload paused
 */
Tine.Filemanager.nodeActions.ResumeUploadAction = {};

/**
 * one or multiple file nodes currently uploaded or upload paused
 * @TODO deletes node as well?
 */
Tine.Filemanager.nodeActions.CancelUploadAction = {};


/***/ }),

/***/ 18:
/***/ (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' width='42.5' height='42.5'%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;
};


/***/ }),

/***/ 20:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath d='M28.7,31.9c0-0.3-0.1-0.6-0.3-0.8s-0.5-0.3-0.8-0.3c-0.3,0-0.6,0.1-0.8,0.3s-0.3,0.5-0.3,0.8s0.1,0.6,0.3,0.8 c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.6-0.1,0.8-0.3C28.6,32.5,28.7,32.3,28.7,31.9z M33.2,31.9c0-0.3-0.1-0.6-0.3-0.8s-0.5-0.3-0.8-0.3 s-0.6,0.1-0.8,0.3s-0.3,0.5-0.3,0.8s0.1,0.6,0.3,0.8c0.2,0.2,0.5,0.3,0.8,0.3s0.6-0.1,0.8-0.3C33.1,32.5,33.2,32.3,33.2,31.9z M35.5,28v5.7c0,0.5-0.2,0.9-0.5,1.2s-0.7,0.5-1.2,0.5H7.7c-0.5,0-0.9-0.2-1.2-0.5C6.2,34.5,6,34.1,6,33.6V28c0-0.5,0.2-0.9,0.5-1.2 c0.3-0.3,0.7-0.5,1.2-0.5h7.6c0.2,0.7,0.7,1.2,1.2,1.6c0.6,0.4,1.2,0.6,2,0.6H23c0.7,0,1.4-0.2,2-0.6s1-1,1.2-1.6h7.6 c0.5,0,0.9,0.2,1.2,0.5C35.3,27.1,35.5,27.5,35.5,28z M11.8,16.8c0.2-0.5,0.5-0.7,1-0.7h4.5V8.1c0-0.3,0.1-0.6,0.3-0.8 C17.9,7.1,18.2,7,18.5,7H23c0.3,0,0.6,0.1,0.8,0.3c0.2,0.2,0.3,0.5,0.3,0.8v7.9h4.5c0.5,0,0.8,0.2,1,0.7c0.2,0.5,0.1,0.9-0.2,1.2 l-7.9,7.9c-0.2,0.2-0.5,0.3-0.8,0.3s-0.6-0.1-0.8-0.3L12,18C11.6,17.6,11.6,17.2,11.8,16.8z'/%3E %3C/svg%3E\""

/***/ }),

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

__webpack_require__(630);
__webpack_require__(631);
__webpack_require__(632);
__webpack_require__(633);
__webpack_require__(634);
__webpack_require__(635);
__webpack_require__(636);
__webpack_require__(637);
__webpack_require__(638);
__webpack_require__(639);
__webpack_require__(640);
__webpack_require__(641);
__webpack_require__(642);
__webpack_require__(643);
__webpack_require__(644);
__webpack_require__(645);
__webpack_require__(646);
__webpack_require__(648);
__webpack_require__(649);
__webpack_require__(650);
__webpack_require__(651);
__webpack_require__(652);
__webpack_require__(662);


/***/ }),

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

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2007-2014 Metaways Infosystems GmbH (http://www.metaways.de)
 */

Ext.ns('Tine.Filemanager');

/**
 * generic exception handler for filemanager
 * 
 * @namespace Tine.Filemanager
 * @param {Tine.Exception} exception
 * @param {Object} request
 */
Tine.Filemanager.handleRequestException = function(exception, request) {

    var app = Tine.Tinebase.appMgr.get('Filemanager'),
        existingFilenames = [],
        nonExistantFilenames = [],
        i,
        filenameWithoutPath = null;

    switch(exception.code) {
        // overwrite default 503 handling and add a link to the wiki
        case 503:
            Ext.MessageBox.show({
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.WARNING,
                title: i18n._('Service Unavailable'),
                msg: String.format(app.i18n._('The Filemanager is not configured correctly. Please refer to the {0}Tine 2.0 Admin FAQ{1} for configuration advice or contact your administrator.'),
                    '<a href="http://wiki.tine20.org/Admin_FAQ#The_message_.22filesdir_config_value_not_set.22_appears_in_the_logfile_and_I_can.27t_open_the_Filemanager" target="_blank">',
                    '</a>')
            });
            break;

        case 901:
            if (request) {
                Tine.log.debug('Tine.Filemanager.handleRequestException - request exception:');
                Tine.log.debug(exception);

                if (exception.existingnodesinfo) {
                    for (i = 0; i < exception.existingnodesinfo.length; i++) {
                        existingFilenames.push(Ext.util.Format.htmlEncode(exception.existingnodesinfo[i].name));
                    }
                }

                this.conflictConfirmWin = Tine.widgets.dialog.FileListDialog.openWindow({
                    modal: true,
                    allowCancel: false,
                    height: 180,
                    width: 300,
                    title: app.i18n._('Files already exists') + '. ' + app.i18n._('Do you want to replace the following file(s)?'),
                    text: existingFilenames.join('<br />'),
                    scope: this,
                    handler: function(button) {
                        var params = request.params,
                            uploadKey = exception.uploadKeyArray;
                        params.method = request.method;
                        params.forceOverwrite = true;

                        if (button == 'no') {
                            if (params.method == 'Filemanager.moveNodes') {
                                // reload grid
                                var app = Tine.Tinebase.appMgr.get('Filemanager');
                                app.getMainScreen().getCenterPanel().grid.getStore().reload();
                                // do nothing, other nodes has been moved already
                                return;
                            }
                            
                            Tine.log.debug('Tine.Filemanager.handleRequestException::' + params.method + ' -> only non-existant nodes.');
                            
                            Ext.each(params.filenames, function(filename) {
                                filenameWithoutPath = filename.match(/[^\/]*$/);
                                if (filenameWithoutPath && existingFilenames.indexOf(filenameWithoutPath[0]) === -1) {
                                    nonExistantFilenames.push(filename);
                                }
                            });
                            
                            params.filenames = nonExistantFilenames;
                            
                            uploadKey = nonExistantFilenames;
                        } else {
                            Tine.log.debug('Tine.Filemanager.handleRequestException::' + params.method + ' -> replace all existing nodes.');
                        }

                        if (params.method == 'Filemanager.copyNodes' || params.method == 'Filemanager.moveNodes' ) {
                            Tine.Filemanager.fileRecordBackend.copyNodes(null, null, null, params);
                        } else if (params.method == 'Filemanager.createNodes' ) {
                            Tine.Filemanager.fileRecordBackend.createNodes(params, uploadKey, exception.addToGridStore);
                        }
                    }
                });

            } else {
                Ext.Msg.show({
                  title:   app.i18n._('Failure on create folder'),
                  msg:     app.i18n._('Item with this name already exists!'),
                  icon:    Ext.MessageBox.ERROR,
                  buttons: Ext.Msg.OK
               });
            }
            break;
        case 902: // Filemanager_Exception_DestinationIsOwnChild
            Ext.MessageBox.show({
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.ERROR,
                title: app.i18n._(exception.title),
                msg: app.i18n._(exception.message)
            });
            break;
        case 903: // Filemanager_Exception_DestinationIsSameNode
            Ext.MessageBox.show({
                buttons: Ext.Msg.OK,
                icon: Ext.MessageBox.INFO,
                title: app.i18n._(exception.title),
                msg: app.i18n._(exception.message)
            });
            break;
        default:
            Tine.Tinebase.ExceptionHandler.handleRequestException(exception);
            break;
    }
};

/***/ }),

/***/ 631:
/***/ (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-2014 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager.Model');
    
/**
 * @namespace   Tine.Filemanager.Model
 * @class       Tine.Filemanager.Model.Node
 * @extends     Tine.Tinebase.data.Record
 * Example record definition
 * 
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 */
Tine.Filemanager.Model.Node = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.Tree_NodeArray, {
    appName: 'Filemanager',
    modelName: 'Node',
    idProperty: 'id',
    titleProperty: 'name',
    // ngettext('File', 'Files', n); gettext('File');
    recordName: 'File',
    recordsName: 'Files',
    // ngettext('Folder', 'Folders', n); gettext('Folder');
    containerName: 'Folder',
    containersName: 'Folders',

    
    isDropFilesAllowed: function() {
        var grants = this.get('account_grants');
        if(!grants) {
            return false;
        }
        else if(!grants.addGrant) {
            return false;
        }
        return true;
    },

    /**
     * virtual nodes are part of the tree but don't exists / are editable
     *
     * NOTE: only "real" virtual node is node with path "otherUsers". all other nodes exist
     *
     * @returns {boolean}
     */
    isVirtual: function() {
        var _ = window.lodash,
            path = this.get('path'),
            parts = _.trim(path, '/').split('/');

        return _.indexOf(['/', '/personal', '/shared'], path) >= 0 || (parts.length == 2 && parts[0] == 'personal');
    },

    getSystemLink: function() {
        var _ = window.lodash,
            encodedPath = _.map(String(this.get('path')).replace(/(^\/|\/$)/, '').split('/'), Ext.ux.util.urlCoder.encodeURIComponent).join('/');

        return [Tine.Tinebase.common.getUrl().replace(/\/$/, ''), '#/Filemanager/showNode', encodedPath].join('/');


    }
});

// register grants for nodes
Tine.widgets.container.GrantsManager.register('Filemanager_Model_Node', function(container) {
    // TODO get default grants and remove export
    // var grants = Tine.widgets.container.GrantsManager.defaultGrants();
    //grants.push('download', 'publish');
    var grants = ['read', 'add', 'edit', 'delete', 'sync', 'download', 'publish'];

    return grants;
});

Ext.override(Tine.widgets.container.GrantsGrid, {
    downloadGrantTitle: 'Download', // i18n._('Download')
    downloadGrantDescription: 'The grant to download files', // i18n._('The grant to download files')
    publishGrantTitle: 'Publish', // i18n._('Publish')
    publishGrantDescription: 'The grant to create anonymous download links for files', // i18n._('The grant to create anonymous download links for files')
});

/**
 * create Node from File
 * 
 * @param {File} file
 */
Tine.Filemanager.Model.Node.createFromFile = function(file) {
    return new Tine.Filemanager.Model.Node({
        name: file.name ? file.name : file.fileName,  // safari and chrome use the non std. fileX props
        size: file.size || 0,
        type: 'file',
        contenttype: file.type ? file.type : file.fileType, // missing if safari and chrome 
        revision: 0
    });
};

// NOTE: atm the activity records are stored as Tinebase_Model_Tree_Node records
Tine.widgets.grid.RendererManager.register('Tinebase', 'Tree_Node', 'revision', function(revision, metadata, record) {
    revision = parseInt(revision, 10);
    var revisionString = Tine.Tinebase.appMgr.get('Filemanager').i18n._('Revision') + " " + revision,
        availableRevisions = record.get('available_revisions');

    // NOTE we have to encode the path here because it might contain quotes or other bad chars
    if (Ext.isArray(availableRevisions) && availableRevisions.indexOf(String(revision)) >= 0) {
       /* if (revision.is_quarantined == '1') {
            return '<img src="images/icon-set/icon_virus.svg" >' + revisionString; @ToDo needs field revision_quarantine
        }*/
        return '<a href="#"; onclick="Tine.Filemanager.downloadFileByEncodedPath(\'' + btoa(record.get('path')) + '\',' + revision
            + '); return false;">' + revisionString + '</a>';

    }else {
        return revisionString;
    }
});


/**
 * default ExampleRecord backend
 */
Tine.Filemanager.FileRecordBackend = Ext.extend(Tine.Tinebase.data.RecordProxy, {
    appName: 'Filemanager',
    modelName: 'Node',
    recordClass: Tine.Filemanager.Model.Node,
    
    /**
     * creating folder
     * 
     * @param name      folder name
     * @param options   additional options
     * @returns
     */
    createFolder: function(name, options) {
        
        options = options || {};
        var params = {
                application : this.appName,
                filename : name,
                type : 'folder',
                method : this.appName + ".createNode"  
        };
        
        options.params = params;
        
        options.beforeSuccess = function(response) {
            var folder = this.recordReader(response);
            folder.set('client_access_time', new Date());
            this.postMessage('create', folder.data);
            return [folder];
        };

        return this.doXHTTPRequest(options);
    },
    
    /**
     * is automatically called in generic GridPanel
     */
    saveRecord : function(record, request) {
        if(record.hasOwnProperty('fileRecord')) {
            return;
        } else {
            Tine.Tinebase.data.RecordProxy.prototype.saveRecord.call(this, record, request);
        }
    },

    /**
     * deleting file or folder
     *
     * overridden cause json fe works on filenames / not id's
     *
     * @param items     files/folders to delete
     * @param options   additional options
     * @returns
     */
    deleteItems: function(items, options) {
        options = options || {};

        var _ = window.lodash,
            me = this,
            filenames = new Array(),
            nodeCount = items.length;

        for(var i=0; i<nodeCount; i++) {
            filenames.push(items[i].data.path );
        }

        var params = {
            application: this.appName,
            filenames: filenames,
            method: this.appName + ".deleteNodes",
            timeout: 300000 // 5 minutes
        };

        options.params = params;

        options.beforeSuccess = function(response) {
            var folder = this.recordReader(response);
            folder.set('client_access_time', new Date());
            return [folder];
        };

        // announce delte before server delete to improve ux
        _.each(items, function(record) {
            me.postMessage('delete', record.data);
        });

        return this.doXHTTPRequest(options);
    },
    
    /**
     * copy/move folder/files to a folder
     *
     * @param items files/folders to copy
     * @param targetPath
     *
     * @param move
     */
    copyNodes : function(items, target, move, params) {
        
        var message = '',
            app = Tine.Tinebase.appMgr.get(this.appName);
        
        if(!params) {
        
            if(!target || !items || items.length < 1) {
                return false;
            }
            
            var sourceFilenames = new Array(),
                destinationFilenames = new Array(),
                forceOverwrite = false,
                treeIsTarget = false,
                targetPath = target;
            
            if(target.data) {
                targetPath = target.data.path + (target.data.type == 'folder' ? '/' : '');
            }
            else if (target.attributes) {
                targetPath = target.attributes.path + '/';
                treeIsTarget = true;
            }
            else if (target.path) {
                targetPath = target.path + (target.type == 'folder' ? '/' : '');
            }

            for(var i=0; i<items.length; i++) {
                var item = items[i];
                var itemData = item.data;
                if(!itemData) {
                    itemData = item.attributes;
                }
                sourceFilenames.push(itemData.path);
                
                var itemName = itemData.name;
                if(typeof itemName == 'object') {
                    itemName = itemName.name;
                }

                destinationFilenames.push(targetPath + (targetPath.match(/\/$/) ? itemName : ''));
            }
            
            var method = this.appName + ".copyNodes",
                message = app.i18n._('Copying data .. {0}');
            if(move) {
                method = this.appName + ".moveNodes";
                message = app.i18n._('Moving data .. {0}');
            }
            
            params = {
                    application: this.appName,
                    sourceFilenames: sourceFilenames,
                    destinationFilenames: destinationFilenames,
                    forceOverwrite: forceOverwrite,
                    method: method
            };
            
        } else {
            message = app.i18n._('Copying data .. {0}');
            if(params.method == this.appName + '.moveNodes') {
                message = app.i18n._('Moving data .. {0}');
            }
        }
        
        this.loadMask = new Ext.LoadMask(app.getMainScreen().getCenterPanel().getEl(), {msg: String.format(i18n._('Please wait')) + '. ' + String.format(message, '' )});
        app.getMainScreen().getWestPanel().setDisabled(true);
        app.getMainScreen().getNorthPanel().setDisabled(true);
        this.loadMask.show();
        
        Ext.Ajax.request({
            params: params,
            timeout: 300000, // 5 minutes
            scope: this,
            success: function(result, request){
                
                this.loadMask.hide();
                app.getMainScreen().getWestPanel().setDisabled(false);
                app.getMainScreen().getNorthPanel().setDisabled(false);

                // send updates
                var _ = window.lodash,
                    me = this,
                    recordsData = Ext.util.JSON.decode(result.responseText);

                _.each(recordsData, function(recordData) {
                    me.postMessage('update', recordData);
                });


                // var nodeData = Ext.util.JSON.decode(result.responseText),
                //     treePanel = app.getMainScreen().getWestPanel().getContainerTreePanel(),
                //     grid = app.getMainScreen().getCenterPanel();
                //
                // // Tree refresh
                // if(treeIsTarget) {
                //
                //     for(var i=0; i<items.length; i++) {
                //
                //         var nodeToCopy = items[i];
                //
                //         if(nodeToCopy.data && nodeToCopy.data.type !== 'folder') {
                //             continue;
                //         }
                //
                //         if(move) {
                //             var copiedNode = treePanel.cloneTreeNode(nodeToCopy, target),
                //                 nodeToCopyId = nodeToCopy.id,
                //                 removeNode = treePanel.getNodeById(nodeToCopyId);
                //
                //             if(removeNode && removeNode.parentNode) {
                //                 removeNode.parentNode.removeChild(removeNode);
                //             }
                //
                //             target.appendChild(copiedNode);
                //             copiedNode.setId(nodeData[i].id);
                //         }
                //         else {
                //             var copiedNode = treePanel.cloneTreeNode(nodeToCopy, target);
                //             target.appendChild(copiedNode);
                //             copiedNode.setId(nodeData[i].id);
                //
                //         }
                //     }
                // }
                //
                // // Grid refresh
                // grid.getStore().reload();
            },
            failure: function(response, request) {
                var nodeData = Ext.util.JSON.decode(response.responseText),
                    request = Ext.util.JSON.decode(request.jsonData);
                
                this.loadMask.hide();
                app.getMainScreen().getWestPanel().setDisabled(false);
                app.getMainScreen().getNorthPanel().setDisabled(false);
                
                Tine.Filemanager.fileRecordBackend.handleRequestException(nodeData.data, request);
            }
        });
    },
    
    /**
     * upload file 
     * 
     * @param {} params Request parameters
     * @param String uploadKey
     * @param Boolean addToGridStore 
     */
    createNode: function(params, uploadKey, addToGridStore) {
        var app = Tine.Tinebase.appMgr.get(this.appName),
            me = this,
            grid = app.getMainScreen().getCenterPanel(),
            gridStore = grid.getStore();
        
        params.application = this.appName;
        params.method = this.appName + '.createNode';
        params.uploadKey = uploadKey;
        params.addToGridStore = addToGridStore;
        
        var onSuccess = (function(result, request){

            var nodeData = Ext.util.JSON.decode(response.responseText),
                fileRecord = Tine.Tinebase.uploadManager.upload(this.uploadKey);

            fileRecord.on('update', me.onUploadUpdate.createDelegate(me));

            if(addToGridStore) {
                var recordToRemove = gridStore.query('name', fileRecord.get('name'));
                if(recordToRemove.items[0]) {
                    gridStore.remove(recordToRemove.items[0]);
                }
                
                fileRecord = Tine.Filemanager.fileRecordBackend.updateNodeRecord(nodeData[i], fileRecord);
                var nodeRecord = new Tine.Filemanager.Model.Node(nodeData[i]);
                
                nodeRecord.fileRecord = fileRecord;
                gridStore.add(nodeRecord);
                
            }
        }).createDelegate({uploadKey: uploadKey, addToGridStore: addToGridStore});
        
        var onFailure = (function(response, request) {
            
            var nodeData = Ext.util.JSON.decode(response.responseText);
            request = Ext.util.JSON.decode(request.jsonData);
            
            nodeData.data.uploadKey = this.uploadKey;
            nodeData.data.addToGridStore = this.addToGridStore;
            Tine.Filemanager.fileRecordBackend.handleRequestException(nodeData.data, request);
            
        }).createDelegate({uploadKey: uploadKey, addToGridStore: addToGridStore});
        
        Ext.Ajax.request({
            params: params,
            timeout: 300000, // 5 minutes
            scope: this,
            success: onSuccess || Ext.emptyFn,
            failure: onFailure || Ext.emptyFn
        });
    },
    
    /**
     * upload files
     * 
     * @param {} params Request parameters
     * @param [] uploadKeyArray
     * @param Boolean addToGridStore
     */
    createNodes: function (params, uploadKeyArray, addToGridStore) {
        var app = Tine.Tinebase.appMgr.get(this.appName),
            grid = app.getMainScreen().getCenterPanel(),
            me = this,
            gridStore = grid.store;

        params.application = this.appName;
        params.method = this.appName + '.createNodes';
        params.uploadKeyArray = uploadKeyArray;
        params.addToGridStore = addToGridStore;


        var onSuccess = (function (response, request) {

            var nodeData = Ext.util.JSON.decode(response.responseText);

            for (var i = 0; i < this.uploadKeyArray.length; i++) {
                var fileRecord = Tine.Tinebase.uploadManager.upload(this.uploadKeyArray[i]);

                Tine.Tinebase.uploadManager.getUpload(this.uploadKeyArray[i]).on('update', me.onUploadUpdate.createDelegate(me));

                if (addToGridStore) {
                    fileRecord = Tine.Filemanager.fileRecordBackend.updateNodeRecord(nodeData[i], fileRecord);
                    var nodeRecord = new Tine.Filemanager.Model.Node(nodeData[i]);

                    nodeRecord.fileRecord = fileRecord;

                    var existingRecordIdx = gridStore.find('name', fileRecord.get('name'));
                    if (existingRecordIdx > -1) {
                        gridStore.removeAt(existingRecordIdx);
                        gridStore.insert(existingRecordIdx, nodeRecord);
                    } else {
                        gridStore.add(nodeRecord);
                    }
                }
            }

        }).createDelegate({uploadKeyArray: uploadKeyArray, addToGridStore: addToGridStore});

        var onFailure = (function (response, request) {

            var nodeData = Ext.util.JSON.decode(response.responseText),
                request = Ext.util.JSON.decode(request.jsonData);

            nodeData.data.uploadKeyArray = this.uploadKeyArray;
            nodeData.data.addToGridStore = this.addToGridStore;
            Tine.Filemanager.fileRecordBackend.handleRequestException(nodeData.data, request);

        }).createDelegate({uploadKeyArray: uploadKeyArray, addToGridStore: addToGridStore});

        Ext.Ajax.request({
            params: params,
            timeout: 300000, // 5 minutes
            scope: this,
            success: onSuccess || Ext.emptyFn,
            failure: onFailure || Ext.emptyFn
        });
    },

    /**
     * Is fired if there is any change for an uploading file
     *
     * Is bind to the record proxy scope
     */
    onUploadUpdate: function (change, upload, fileRecord) {
        var app = Tine.Tinebase.appMgr.get(this.appName),
            grid = app.getMainScreen().getCenterPanel(),
            rowsToUpdate = grid.store.query('name', fileRecord.get('name'));

        if (change === 'uploadstart') {
            Tine.Tinebase.uploadManager.onUploadStart();
        } else if (change === 'uploadfailure') {
            if (Ext.isFunction(grid.onUploadFail)) {
                grid.onUploadFail();
            } else {
                // TODO do something on failure?
            }
        }

        if (rowsToUpdate.get(0)) {
            if (change === 'uploadcomplete') {
                this.onUploadComplete.call(grid, this, upload, fileRecord);
            } else if (change === 'uploadfinished') {
                rowsToUpdate.get(0).set('size', fileRecord.get('size'));
                rowsToUpdate.get(0).set('contenttype', fileRecord.get('contenttype'));
            }

            rowsToUpdate.get(0).afterEdit();
            rowsToUpdate.get(0).commit(false);
        }
    },

    /**
     * updating fileRecord after creating node
     *
     * @param response
     * @param request
     * @param upload
     */
    onNodeCreated: function (response, request, upload) {
        var record = Ext.util.JSON.decode(response.responseText);

        var fileRecord = upload.fileRecord;
        fileRecord.beginEdit();
        fileRecord.set('contenttype', record.contenttype);
        fileRecord.set('created_by', Tine.Tinebase.registry.get('currentAccount'));
        fileRecord.set('creation_time', record.creation_time);
        fileRecord.set('revision', record.revision);
        fileRecord.set('last_modified_by', record.last_modified_by);
        fileRecord.set('last_modified_time', record.last_modified_time);
        fileRecord.set('name', record.name);
        fileRecord.set('path', record.path);
        fileRecord.set('status', 'complete');
        fileRecord.set('progress', 100);
        fileRecord.commit(false);

        upload.fireEvent('update', 'uploadfinished', upload, fileRecord);

        var allRecordsComplete = true;
        var storeItems = this.getStore().getRange();
        for (var i = 0; i < storeItems.length; i++) {
            if (storeItems[i].get('status') && storeItems[i].get('status') !== 'complete') {
                allRecordsComplete = false;
                break;
            }
        }

        if (allRecordsComplete) {
            this.pagingToolbar.refresh.enable();
        }
    },

    /**
     * copies uploaded temporary file to target location
     *
     * @param proxy  {Tine.Filemanager.fileRecordBackend}
     * @param upload  {Ext.ux.file.Upload}
     * @param file  {Ext.ux.file.Upload.file}
     */
    onUploadComplete: function(proxy, upload, file) {
        Ext.Ajax.request({
            timeout: 10*60*1000, // Overriding Ajax timeout - important!
            params: {
                method: proxy.appName + '.createNode',
                filename: upload.id,
                type: 'file',
                tempFileId: file.get('id'),
                forceOverwrite: true
            },
            success: proxy.onNodeCreated.createDelegate(this, [upload], true),
            failure: function(response, request) {
                let app = Tine.Tinebase.appMgr.get('Filemanager');
                let msg = app.formatMessage('Error while uploading "{fileName}". Please try again later.',
                    {fileName: file.get('name') });

                Ext.MessageBox.alert(app.formatMessage('Upload Failed'), msg)
                    .setIcon(Ext.MessageBox.ERROR);

            }
        });

    },

    /**
     * exception handler for this proxy
     * 
     * @param {Tine.Exception} exception
     */
    handleRequestException: function(exception, request) {
        var _ = window.lodash,
            appNS = _.get(Tine, this.appName);
        appNS.handleRequestException(exception, request);
    },
    
    /**
     * updates given record with nodeData from from response
     */
    updateNodeRecord : function(nodeData, nodeRecord) {
        
        for(var field in nodeData) {
            nodeRecord.set(field, nodeData[field]);
        }
        
        return nodeRecord;
    }
});
Tine.Filemanager.fileRecordBackend = new Tine.Filemanager.FileRecordBackend({});

/**
 * get filtermodel of Node records
 * 
 * @namespace Tine.Filemanager.Model
 * @static
 * @return {Object} filterModel definition
 */ 
Tine.Filemanager.Model.Node.getFilterModel = function() {
    var app = Tine.Tinebase.appMgr.get('Filemanager');
       
    return [
        {label : i18n._('Quick Search'), field : 'query', operators : [ 'contains' ]},
//        {label: app.i18n._('Type'), field: 'type'}, // -> should be a combo
        {label: app.i18n._('Contenttype'), field: 'contenttype'},
        {label: app.i18n._('Creation Time'), field: 'creation_time', valueType: 'date'},
        {label: app.i18n._('Description'), field: 'description', valueType: 'fulltext'},
        {filtertype : 'tine.filemanager.pathfiltermodel', app : app},
        {filtertype : 'tinebase.tag', app : app} 
    ].concat(Tine.Tinebase.configManager.get('filesystem.index_content', 'Tinebase') ? [
        {label : app.i18n._('File Contents'), field : 'content', operators : [ 'wordstartswith' ]},
        {label : i18n._('Indexed'), field : 'isIndexed', valueType: 'bool'}
    ] : []);
};

/**
 * @namespace   Tine.Filemanager.Model
 * @class       Tine.Filemanager.Model.DownloadLink
 * @extends     Tine.Tinebase.data.Record
 * Example record definition
 */
Tine.Filemanager.Model.DownloadLink = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.modlogFields.concat([
    { name: 'id' },
    { name: 'node_id' },
    { name: 'url' },
    { name: 'expiry_time', type: 'datetime' },
    { name: 'access_count' },
    { name: 'password' }
]), {
    appName: 'Filemanager',
    modelName: 'DownloadLink',
    idProperty: 'id',
    titleProperty: 'url',
    // ngettext('Download Link', 'Download Links', n); gettext('Download Link');
    recordName: 'Download Link',
    recordsName: 'Download Links'
});

/**
 * download link backend
 */
Tine.Filemanager.downloadLinkRecordBackend = new Tine.Tinebase.data.RecordProxy({
    appName: 'Filemanager',
    modelName: 'DownloadLink',
    recordClass: Tine.Filemanager.Model.DownloadLink
});


/***/ }),

/***/ 632:
/***/ (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) 2010-2012 Metaways Infosystems GmbH (http://www.metaways.de)
 * 
 */
Ext.ns('Tine.Filemanager');

/**
 * @namespace   Tine.widgets.container
 * @class       Tine.Filemanager.PathFilterModel
 * @extends     Tine.widgets.grid.FilterModel
 * 
 * @author      Cornelius Weiss <c.weiss@metaways.de>
 * 
 * @TODO make valueRenderer a path picker widget
 */
Tine.Filemanager.PathFilterModel = Ext.extend(Tine.widgets.grid.FilterModel, {
    /**
     * @cfg {Tine.Tinebase.Application} app
     */
    app: null,
    
    /**
     * @cfg {Array} operators allowed operators
     */
    operators: ['equals'],
    
    /**
     * @cfg {String} field path
     */
    field: 'path',
    
    /**
     * @cfg {String} defaultOperator default operator, one of <tt>{@link #operators} (defaults to equals)
     */
    defaultOperator: 'equals',
    
    /**
     * @cfg {String} defaultValue default value (defaults to all)
     */
    defaultValue: '/',
    
    /**
     * @private
     */
    initComponent: function() {
        this.label = this.app.i18n._('path');
        
        Tine.Filemanager.PathFilterModel.superclass.initComponent.call(this);
    },
    
    /**
     * value renderer
     * 
     * @param {Ext.data.Record} filter line
     * @param {Ext.Element} element to render to 
     */
    valueRenderer: function(filter, el) {
        var setValue = function(value) {
            if (value && value.path) {
                value = value.path;
            }
            else if(Ext.isString(value) && (!value.charAt(0) || value.charAt(0) != '/')) {
                value = '/' + value;
            }

            return Ext.ux.form.ClearableTextField.prototype.setValue.call(this, value);
        };

        var value = new Ext.ux.form.ClearableTextField({
            filter: filter,
            width: this.filterValueWidth,
            id: 'tw-ftb-frow-valuefield-' + filter.id,
            renderTo: el,
            value: filter.data.value ? filter.data.value : this.defaultValue,
            emptyText: this.emptyText,
            setValue: setValue
        });
        
        value.on('specialkey', function(field, e){
            if(e.getKey() == e.ENTER){
                this.onFiltertrigger();
            }
        }, this);

        return value;
    }
});

Tine.widgets.grid.FilterToolbar.FILTERS['tine.filemanager.pathfiltermodel'] = Tine.Filemanager.PathFilterModel;



/***/ }),

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

/*
 * Tine 2.0
 * Filemanager combo box and store
 * 
 * @package     Filemanager
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @author      Michael Spahn <m.spahn@metaways.de>
 * @copyright   Copyright (c) 2012-2017 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 */

Ext.ns('Tine.Filemanager');

/**
 * Node selection combo box
 * 
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.SearchCombo
 * @extends     Ext.form.TriggerField
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @author      Michael Spahn <m.spahn@metaways.de>
 * @copyright   Copyright (c) 2012-2017 Metaways Infosystems GmbH (http://www.metaways.de)
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Filemanager.SearchCombo
 */
Tine.Filemanager.SearchCombo = Ext.extend(Ext.form.TriggerField, {
    
    allowBlank: false,
    singleSelect: true,
    constraint: 'file',

    itemSelector: 'div.search-item',
    minListWidth: 200,

    app: null,
    
    recordClass: null,
    recordProxy: null,
    
    initComponent: function(){
        this.recordClass = Tine.Filemanager.Model.Node;
        this.recordProxy = Tine.Filemanager.fileRecordBackend;

        if (null === this.app) {
            this.app = Tine.Tinebase.appMgr.get('Filemanager');
        }

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

        this.addEvents(
            /**
             * @param selected node
             */
            'select'
        );
    },
    
    onTriggerClick: function () {
        var filepicker = new Tine.Filemanager.FilePickerDialog({
            windowTitle: this.title,
            singleSelect: this.singleSelect,
            constraint: this.constraint
        });

        filepicker.on('selected', function (node) {
            if (!node || 0 === node.length) {
                return true;
            }

            this.fireEvent('select', node[0]);
            this.setValue(node[0].path);

        }, this);

        filepicker.openWindow();
    }
});

Tine.widgets.form.RecordPickerManager.register('Filemanager', 'Node', Tine.Filemanager.SearchCombo);


/***/ }),

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

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

Ext.ns('Tine.Filemanager');

__webpack_require__(177);

/**
 * @namespace Tine.Filemanager
 * @class Tine.Filemanager.NodeTreePanel
 * @extends Tine.widgets.container.TreePanel
 *
 * @author Martin Jatho <m.jatho@metaways.de>
 */
Tine.Filemanager.NodeTreePanel = Ext.extend(Tine.widgets.container.TreePanel, {

    filterMode : 'filterToolbar',

    recordClass : Tine.Filemanager.Model.Node,

    allowMultiSelection : false,

    ddGroup: 'fileDDGroup',
    enableDD: true,

    dataSafeAreaName: 'Tinebase.datasafe',
    dataSafeEnabled: false,

    hasGrid: true,

    initComponent: function() {
        this.on('nodedragover', this.onNodeDragOver, this);

        if (! this.app) {
            this.app = Tine.Tinebase.appMgr.get(this.recordClass.getMeta('appName'));
        }

        if (this.readOnly) {
            this.enableDD = false;
        }

        // NOTE: fm tree is initially loaded from grid!
        // this.defaultContainerPath = Tine.Tinebase.container.getMyFileNodePath();

        this.dragConfig = {
            ddGroup: this.ddGroup,
            scroll: this.ddScroll,
            onBeforeDrag: this.onBeforeDrag.createDelegate(this)
        };

        this.dropConfig = {
            ddGroup: this.ddGroup,
            appendOnly: this.ddAppendOnly === true,
            onNodeOver: this.onNodeOver.createDelegate(this)
        };

        Tine.Filemanager.NodeTreePanel.superclass.initComponent.call(this);

        this.plugins = this.plugins || [];

        if (!this.readOnly && this.enableDD) {
            this.plugins.push({
                ptype : 'ux.browseplugin',
                enableFileDialog: false,
                multiple : true,
                handler : this.dropIntoTree
            });
        }

        postal.subscribe({
            channel: "recordchange",
            topic: [this.recordClass.getMeta('appName'), this.recordClass.getMeta('modelName'), '*'].join('.'),
            callback: this.onRecordChanges.createDelegate(this)
        });

        this.dataSafeEnabled = Tine.Tinebase.areaLocks.hasLock(this.dataSafeAreaName);
        if (this.dataSafeEnabled) {
            postal.subscribe({
                channel: 'areaLocks',
                topic: this.dataSafeAreaName +'.*',
                callback: this.applyDataSafeState.createDelegate(this)
            });

            this.dataSafeIsLocked = Tine.Tinebase.areaLocks.isLocked(this.dataSafeAreaName)
        }
    },

    onRecordChanges: function(data, e) {
        if (data.type == 'folder') {
            var _ = window.lodash,
                me = this,
                path = data.path,
                parentPath = path.replace(new RegExp(_.escapeRegExp(data.name) + '$'), ''),
                node = this.getNodeById(data.id),
                pathChange = node && node.attributes && node.attributes.nodeRecord.get('path') != path;

            if (node && e.topic.match(/\.delete/)) {
                try {
                    node.cancelExpand();
                    node.remove(true);
                } catch (e) {}
                return;
            }

            if (node) {
                node.setText(Ext.util.Format.htmlEncode(data.name));
                // NOTE: qtip dosn't work, but implementing is not worth the effort...
                node.qtip = Tine.Tinebase.common.doubleEncode(data.name);
                Ext.apply(node.attributes, data);
                node.attributes.nodeRecord = new this.recordClass(data);

                // in case of path change we need to reload the node (children) as well
                // as the path of all children changed as well
                if (node.hasChildNodes() && pathChange && ! node.loading) {
                    if (! node.bufferedReload) {
                        node.bufferedReload = Function.createBuffered(node.reload, 100, node);
                    }
                    node.bufferedReload();
                }
            }

            // add / remount node
            try {
                me.expandPath(parentPath, '', function (sucess, parentNode) {
                    var childNode = parentNode.findChild('name', data.name);
                    if (!childNode) {
                        parentNode.appendChild(node || me.loader.createNode(data));
                    } else if (childNode != node) {
                        // node got duplicated by expand load
                        try {
                            node.cancelExpand();
                            node.remove(true);
                        } catch (e) {
                        }
                    }
                });
            } catch (e) {}
        }
    },

    applyDataSafeState: function() {
        var me = this;

        Tine.Tinebase.areaLocks.isLocked(me.dataSafeAreaName).then(function(isLocked) {
            me.dataSafeIsLocked.then(function(wasLocked) {
                me.dataSafeIsLocked = Tine.Tinebase.areaLocks.isLocked(me.dataSafeAreaName);
                if (isLocked != wasLocked) {
                    var rootNode = me.getRootNode(),
                        selectedNode = me.getSelectionModel().getSelectedNode();

                    me.getSelectionModel().suspendEvents();
                    rootNode.collapse(true);
                    // NOTE: the grid reload expands the tree as well!
                    // not clear yet how to detect if a grid is on board as well
                    // if (selectedNode) {
                    //     me.selectPath(selectedNode.attributes.path, {}, me.getSelectionModel().resumeEvents.bind(me));
                    // } else {
                    //     rootNode.expand(false, true,  me.getSelectionModel().resumeEvents.bind(me));
                    // }

                }
            })

        });
    },

    /**
     * autosort new nodes
     *
     * @param tree
     * @param parent
     * @param appendedNode
     * @param idx
     */
    onAppendNode: function(tree, parent, appendedNode, idx) {
        if (parent.getDepth() > 0) {
            parent.sort(function (n1, n2) {
                return n1.text.localeCompare(n2.text);
            });
        }
    },

    /**
     * An empty function by default, but provided so that you can perform a custom action before the initial
     * drag event begins and optionally cancel it.
     * @param {Object} data An object containing arbitrary data to be shared with drop targets
     * @param {Event} e The event object
     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
     */
    onBeforeDrag : function(data, e) {
        var _ = window.lodash,
            requiredGrant = e.ctrlKey || e.altKey ? 'readGrant' : 'editGrant';

        // @TODO: rethink: do I need delte on the record or parent?
        return !! _.get(data, 'node.attributes.nodeRecord.data.account_grants.' + requiredGrant);
    },

    onNodeOver : function(n, dd, e, data) {
        var action = e.ctrlKey || e.altKey ? 'copy' : 'move',
            cls = Ext.tree.TreeDropZone.prototype.onNodeOver.apply(this.dropZone, arguments);

        return cls != this.dropZone.dropNotAllowed ?
            'tinebase-dd-drop-ok-' + action :
            this.dropZone.dropNotAllowed;
    },

    /**
     * @param {Object} dragOverEvent
     *
     * tree - The TreePanel
     * target - The node being targeted for the drop
     * data - The drag data from the drag source
     * point - The point of the drop - append, above or below
     * source - The drag source
     * rawEvent - Raw mouse event
     * dropNode - Drop node(s) provided by the source.
     * cancel - Set this to true to signal drop not allowed.
     */
    onNodeDragOver: function(dragOverEvent) {
        var _ = window.lodash,
            cancel = this.readOnly
                || ! dragOverEvent.target.expanded
                || dragOverEvent.target == dragOverEvent.source.dragData.node
                || ! _.get(dragOverEvent, 'target.attributes.nodeRecord.data.account_grants.addGrant');

        dragOverEvent.cancel = cancel;
    },

    /**
     * files/folder got dropped on node
     *
     * @param {Object} dropEvent
     * @private
     */
    onBeforeNodeDrop: function(dropEvent) {
        var nodes, target = dropEvent.target;

        if(dropEvent.data.selections) {
            nodes = dropEvent.data.grid.selModel.selections.items;
        }

        if(!nodes && dropEvent.data.node) {
            nodes = [dropEvent.data.node];
        }

        Tine[this.appName].fileRecordBackend.copyNodes(nodes, target, !(dropEvent.rawEvent.ctrlKey  || dropEvent.rawEvent.altKey));

        dropEvent.dropStatus = true;
        return true;
    },

    /**
     * load everything from server
     * @returns {Object} root node definition
     */
    getRoot: function() {
        return {
            path: '/',
            cls: 'tinebase-tree-hide-collapsetool'
        };
    },

    /**
     * Tine.widgets.tree.FilterPlugin
     * returns a filter plugin to be used in a grid
     */
    getFilterPlugin: function() {
        if (!this.filterPlugin) {
            this.filterPlugin = new Tine.Filemanager.PathFilterPlugin({
                treePanel: this,
                field: 'path',
                nodeAttributeField: 'path'
            });
        }

        return this.filterPlugin;
    },

    /**
     * returns params for async request
     *
     * @param {Ext.tree.TreeNode} node
     * @return {Object}
     */
    onBeforeLoad: function(node) {
        var path = node.attributes.path;
        var type = Tine.Tinebase.container.path2type(path);
        var owner = Tine.Tinebase.container.pathIsPersonalNode(path);
        var loginName = Tine.Tinebase.registry.get('currentAccount').accountLoginName;

        if (type === 'personal' && owner != loginName) {
            type = 'otherUsers';
        }

        var newPath = path;

        if (type === 'personal' && owner) {
            var pathParts = path.toString().split('/');
            newPath = '/' + pathParts[1] + '/' + loginName;
            if(pathParts[3]) {
                newPath += '/' + pathParts[3];
            }
        }

        var params = {
            method: this.recordClass.getMeta('appName') + '.searchNodes',
            application: this.app.appName,
            owner: owner,
            filter: [
                     {field: 'path', operator:'equals', value: newPath},
                     {field: 'type', operator:'equals', value: 'folder'}
                     ],
            paging: {dir: 'ASC', sort: 'name'}
        };

        return params;
    },

    onBeforeCreateNode: function(attr) {
        Tine.Filemanager.NodeTreePanel.superclass.onBeforeCreateNode.apply(this, arguments);

        attr.leaf = false;

        if(attr.name && typeof attr.name == 'object') {
            Ext.apply(attr, {
                text: Ext.util.Format.htmlEncode(attr.name.name),
                qtip: Tine.Tinebase.common.doubleEncode(attr.name.name)
            });
        }

        // copy 'real' data to a node record NOTE: not a full record as we have no record reader here
        var nodeData = Ext.copyTo({}, attr, this.recordClass.getFieldNames());
        attr.nodeRecord = new this.recordClass(nodeData);

        if(this.dataSafeEnabled && !!attr.nodeRecord.get('pin_protected_node')) {
            attr.cls = 'x-type-data-safe';
        }
    },

    /**
     * initiates tree context menus
     *
     * @private
     */
    initContextMenu: function() {
        this.ctxMenu = Tine.Filemanager.nodeContextMenu.getMenu({
            actionMgr: Tine.Filemanager.nodeActionsMgr,
            nodeName: this.recordClass.getContainerName(),
            actions: ['reload', 'createFolder', 'delete', 'rename', 'move', 'edit', 'publish', 'systemLink'],
            scope: this,
            backend: 'Filemanager',
            backendModel: 'Node'
        });

        this.actionUpdater = new Tine.widgets.ActionUpdater({
            recordClass: this.recordClass,
            actions: this.ctxMenu.items
        });
    },

    /**
     * show context menu
     *
     * @param {Ext.tree.TreeNode} node
     * @param {Ext.EventObject} event
     */
    onContextMenu: function(node, event) {
        event.stopEvent();
        Tine.log.debug(node);

        // legacy for reload action
        this.ctxNode = node;

        //@TODO implement selection vs ctxNode if multiselect is allowed
        var record = new this.recordClass(node.attributes.nodeRecord.data);
        this.actionUpdater.updateActions([record]);

        this.ctxMenu.showAt(event.getXY());
    },

    /**
     * called when tree selection changes
     *
     * @param {} sm     SelectionModel
     * @param {Ext.tree.TreeNode} node
     */
    onSelectionChange: function(sm, node) {
        // this.updateActions(sm, node);
        var grid = this.app.getMainScreen().getCenterPanel(),
            gridSelectionModel = grid.selectionModel,
            actionUpdater = grid.actionUpdater,
            record = node ? new this.recordClass(window.lodash.get(node, 'attributes.nodeRecord.data')) : null,
            selection = record ? [record] : [];

        grid.currentFolderNode = node;

        if (this.hasGrid && gridSelectionModel) {
            gridSelectionModel.clearSelections();
        }

        if (actionUpdater) {
            actionUpdater.updateActions(selection);
        }

        Tine.Filemanager.NodeTreePanel.superclass.onSelectionChange.call(this, sm, node);
    },

    /**
     * convert filesystem path to treePath
     *
     * NOTE: only the first depth gets converted!
     *       fs pathes of not yet loaded tree nodes can't be converted!
     *
     * @param {String} containerPath
     * @return {String} tree path
     */
    getTreePath: function(containerPath) {
        var _ = window.lodash,
            treePath = '/' + this.getRootNode().id + containerPath
            .replace(new RegExp('^' + _.escapeRegExp(Tine.Tinebase.container.getMyFileNodePath())), '/myUser')
            .replace(/^\/personal/, '/otherUsers')
            .replace(/\/$/, '');

        return treePath;
    },

    /**
     * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Ext.data.Node#getPath}
     *
     * NOTE: path does not consist of id's starting from the second depth
     *
     * @param {String} path
     * @param {String} attr (optional) The attribute used in the path (see {@link Ext.data.Node#getPath} for more info)
     * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
     * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
     */
    expandPath : function(path, attr, callback){
        if (! path.match(/^\/xnode-/)) {
            path = this.getTreePath(path);
        }

        var keys = path.split(this.pathSeparator);
        var curNode = this.root;
        var curPath = curNode.attributes.path;
        var index = 1;
        var f = function(){
            if(++index == keys.length){
                if(callback){
                    callback(true, curNode);
                }
                return;
            }

            if (index > 2) {
                var c = curNode.findChild('path', curPath + '/' + keys[index]);
            } else {
                var c = curNode.findChild('id', keys[index]);
            }
            if(!c){
                if(callback){
                    callback(false, curNode);
                }
                return;
            }
            curNode = c;
            curPath = c.attributes.path;
            c.expand(false, false, f);
        };
        curNode.expand(false, false, f);
    },

    /**
     * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Ext.data.Node#getPath}
     * @param {String} path
     * @param {String} attr (optional) The attribute used in the path (see {@link Ext.data.Node#getPath} for more info)
     * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
     * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
     */
    selectPath : function(path, attr, callback) {
        var node = this.expandPath(path, attr, function(bSuccess, oLastNode){
            if (oLastNode) {
                oLastNode.select();
                if (Ext.isFunction(callback)) {
                    callback.call(true, oLastNode);
                }
            }
        }.createDelegate(this));
    },

    /**
     * clone a tree node / create a node from grid node
     *
     * @param node
     * @returns {Ext.tree.AsyncTreeNode}
     */
    cloneTreeNode: function(node, target) {
        var targetPath = target.attributes.path,
            newPath = '',
            copy;

        if(node.attributes) {
            var nodeName = node.attributes.name;
            if(typeof nodeName == 'object') {
                nodeName = nodeName.name;
            }
            newPath = targetPath + '/' + nodeName;

            copy = new Ext.tree.AsyncTreeNode({text: node.text, path: newPath, name: node.attributes.name
                , nodeRecord: node.attributes.nodeRecord, account_grants: node.attributes.account_grants});
        }
        else {
            var nodeName = node.data.name;
            if(typeof nodeName == 'object') {
                nodeName = nodeName.name;
            }

            var nodeData = Ext.copyTo({}, node.data, this.recordClass.getFieldNames());
            var newNodeRecord = new this.recordClass(nodeData);

            newPath = targetPath + '/' + nodeName;
            copy = new Ext.tree.AsyncTreeNode({text: nodeName, path: newPath, name: node.data.name
                , nodeRecord: newNodeRecord, account_grants: node.data.account_grants});
        }

        copy.attributes.nodeRecord.beginEdit();
        copy.attributes.nodeRecord.set('path', newPath);
        copy.attributes.nodeRecord.endEdit();

        copy.parentNode = target;
        return copy;
    },

    /**
     * handels tree drop of object from outside the browser
     *
     * @param fileSelector
     * @param targetNodeId
     */
    dropIntoTree: function(fileSelector, event) {

        var treePanel = fileSelector.component,
            app = treePanel.app,
            grid = app.getMainScreen().getCenterPanel(),
            targetNode,
            targetNodePath;


        var targetNodeId;
        var treeNodeAttribute = event.getTarget('div').attributes['ext:tree-node-id'];
        if(treeNodeAttribute) {
            targetNodeId = treeNodeAttribute.nodeValue;
            targetNode = treePanel.getNodeById(targetNodeId);
            targetNodePath = targetNode.attributes.path;

        }

        if(!targetNode.attributes.nodeRecord.isDropFilesAllowed()) {
            Ext.MessageBox.alert(
                    i18n._('Upload Failed'),
                    app.i18n._('Putting files in this folder is not allowed!')
                ).setIcon(Ext.MessageBox.ERROR);

            return;
        }

        var files = fileSelector.getFileList(),
            filePathsArray = [],
            uploadKeyArray = [],
            addToGridStore = false;

        Ext.each(files, function (file) {
            if ("" === file.type) {
                return true;
            }

            var fileName = file.name || file.fileName,
                filePath = targetNodePath + '/' + fileName;

            var upload = new Ext.ux.file.Upload({
                fmDirector: treePanel,
                file: file,
                fileSelector: fileSelector,
                id: filePath
            });

            var uploadKey = Tine.Tinebase.uploadManager.queueUpload(upload);

            filePathsArray.push(filePath);
            uploadKeyArray.push(uploadKey);

            addToGridStore = grid.currentFolderNode.id === targetNodeId;

        }, this);

        if (0 === uploadKeyArray.length) {
            return;
        }

        var params = {
                filenames: filePathsArray,
                type: "file",
                tempFileIds: [],
                forceOverwrite: false
        };
        Tine.Filemanager.fileRecordBackend.createNodes(params, uploadKeyArray, addToGridStore);
    },


    /**
     * returns true if node can accept contents
     *
     * @param nodeAttributes
     * @returns boolean
     */
    nodeAcceptsContents: function(nodeAttributes) {
        return !! nodeAttributes;
    }
});


/***/ }),

/***/ 635:
/***/ (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) 2010-2012 Metaways Infosystems GmbH (http://www.metaways.de)
 * 
 */
Ext.ns('Tine.Filemanager');

/**
 * filter plugin for container tree
 * 
 * @namespace Tine.widgets.tree
 * @class     Tine.Filemanager.PathFilterPlugin
 * @extends   Tine.widgets.grid.FilterPlugin
 */
Tine.Filemanager.PathFilterPlugin = Ext.extend(Tine.widgets.tree.FilterPlugin, {
    
    /**
     * select tree node(s)
     * 
     * @param {String} value
     */
    selectValue: function(value) {
        var values = Ext.isArray(value) ? value : [value];
        Ext.each(values, function(value) {
            var path = Ext.isString(value) ? value : (value ? value.path : '') || '/',
                treePath = this.treePanel.getTreePath(path);
            
            this.selectPath.call(this.treePanel, treePath, null, function() {
                // mark this expansion as done and check if all are done
                value.isExpanded = true;
                var allValuesExpanded = true;
                Ext.each(values, function(v) {
                    allValuesExpanded &= v.isExpanded;
                }, this);
                
                if (allValuesExpanded) {
                    this.treePanel.getSelectionModel().resumeEvents();
                    
                    // @TODO remove this code when fm is cleaned up conceptually
                    //       currentFolderNode -> currentFolder
                    // this.treePanel.updateActions(this.treePanel.getSelectionModel(), this.treePanel.getSelectionModel().getSelectedNode());
                    // Tine.Tinebase.appMgr.get('Filemanager').getMainScreen().getCenterPanel().currentFolderNode = this.treePanel.getSelectionModel().getSelectedNode();
                }
            }.createDelegate(this), true);
        }, this);
    },

    selectPath: Tine.Filemanager.NodeTreePanel.prototype.selectPath
});


/***/ }),

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

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 * @copyright   Copyright (c) 2012-2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

/**
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.NodeEditDialog
 * @extends     Tine.widgets.dialog.EditDialog
 *
 * <p>Node Compose Dialog</p>
 * <p></p>
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Alexander Stintzing <a.stintzing@metaways.de>
 *
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Filemanager.NodeEditDialog
 */
Tine.Filemanager.NodeEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {

    /**
     * @private
     */
    windowNamePrefix: 'NodeEditWindow_',
    appName: 'Filemanager',
    recordClass: Tine.Filemanager.Model.Node,
    recordProxy: Tine.Filemanager.fileRecordBackend,
    tbarItems: null,
    evalGrants: true,
    showContainerSelector: false,
    displayNotes: true,
    requiredSaveGrant: 'readGrant',

    /**
     * @type Tine.Filemanager.DownloadLinkGridPanel
     */
    downloadLinkGrid: null,

    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('Filemanager');
        this.downloadAction = Tine.Filemanager.nodeActionsMgr.get('download');

        this.tbarItems = [this.downloadAction];

        Tine.Filemanager.NodeEditDialog.superclass.initComponent.call(this);
    },

    /**
     * folder or file?
     */
    getFittingTypeTranslation: function (isWindowTitle) {
        if (isWindowTitle) {
            return this.record.data.type == 'folder' ? this.app.i18n._('Edit folder') : this.app.i18n._('edit file');
        } else {
            return this.record.data.type == 'folder' ? this.app.i18n._('Folder') : this.app.i18n._('File');
        }
    },

    /**
     * executed when record is loaded
     * @private
     */
    onRecordLoad: function() {
        Tine.Filemanager.NodeEditDialog.superclass.onRecordLoad.apply(this, arguments);

        this.window.setTitle(this.getFittingTypeTranslation(true));
    },

    /**
     * returns dialog
     * @return {Object}
     * @private
     */
    getFormItems: function() {
        var me = this,
            _ = window.lodash,
            fsConfig = Tine.Tinebase.configManager.get('filesystem'),
            formFieldDefaults = {
                xtype: 'textfield',
                anchor: '100%',
                labelSeparator: '',
                columnWidth: .5,
                readOnly: true,
                disabled: true
            };

        this.downloadLinkGrid = new Tine.Filemanager.DownloadLinkGridPanel({
            node: this.record,
            app: this.app,
            title: this.app.i18n._('Public Links'),
            editDialog: this
        });

        // require('./GrantsPanel');
        
        var grantsPanel = new Tine.Filemanager.GrantsPanel({
            app: this.app,
            editDialog: this
        });

        if (this.record.data.type !== 'folder') {
            grantsPanel.setDisabled(true);
        }

        var revisionPanel = {};

        if (_.get(fsConfig, 'modLogActive', false)) {
            revisionPanel = new Tine.Filemanager.RevisionPanel({
                editDialog: this
            });
        }

        var items = [{
            title: this.getFittingTypeTranslation(false),
            autoScroll: true,
            border: false,
            frame: true,
            layout: 'border',
            items: [{
                region: 'center',
                layout: 'hfit',
                border: false,
                items: [{
                    xtype: 'fieldset',
                    layout: 'hfit',
                    autoHeight: true,
                    title: this.getFittingTypeTranslation(false),
                    items: [{
                        xtype: 'columnform',
                        labelAlign: 'top',
                        formDefaults: formFieldDefaults,
                        items: [[{
                            fieldLabel: this.app.i18n._('Name'),
                            requiredGrant: 'editGrant',
                            name: 'name',
                            allowBlank: false,
                            readOnly: false,
                            columnWidth: .75,
                            disabled: false
                        }, {
                            fieldLabel: this.app.i18n._('Type'),
                            name: 'contenttype',
                            columnWidth: .25
                        }], [{
                            xtype: 'displayfield',
                            name: 'isIndexed',
                            hideLabel: true,
                            fieldClass: 'x-ux-displayfield-text',
                            width: 10,
                            setValue: function (value) {
                                var string, color, html = '';
                                if (Tine.Tinebase.configManager.get('filesystem.index_content', 'Tinebase') && me.record.get('type') == 'file') {
                                    string = value ? me.app.i18n._('Indexed') : me.app.i18n._('Not yet indexed');
                                    color = value ? 'green' : 'yellow';
                                    html = ['<span style="color:', color, ' !important;" qtip="', string, '">&bull;</span>'].join('');
                                }

                                this.setRawValue(html);
                            }
                        }, {
                            xtype: 'displayfield',
                            name: 'path',
                            hideLabel: true,
                            fieldClass: 'x-ux-displayfield-text',
                            htmlEncode: true,
                            columnWidth: 1
                        }], [
                            Tine.widgets.form.RecordPickerManager.get('Addressbook', 'Contact', {
                                userOnly: true,
                                useAccountRecord: true,
                                blurOnSelect: true,
                                fieldLabel: this.app.i18n._('Created By'),
                                name: 'created_by'
                            }), {
                                fieldLabel: this.app.i18n._('Creation Time'),
                                name: 'creation_time',
                                xtype: 'datefield'
                            }
                        ], [
                            Tine.widgets.form.RecordPickerManager.get('Addressbook', 'Contact', {
                                userOnly: true,
                                useAccountRecord: true,
                                blurOnSelect: true,
                                fieldLabel: this.app.i18n._('Modified By'),
                                name: 'last_modified_by'
                            }), {
                                fieldLabel: this.app.i18n._('Last Modified'),
                                name: 'last_modified_time',
                                xtype: 'datefield'
                            }
                        ]]
                    }]
                }, revisionPanel]
            }, {
                // activities and tags
                layout: 'ux.multiaccordion',
                animate: true,
                region: 'east',
                width: 210,
                split: true,
                collapsible: true,
                collapseMode: 'mini',
                header: false,
                margins: '0 5 0 5',
                border: true,
                items: [
                    new Ext.Panel({
                        title: this.app.i18n._('Description'),
                        iconCls: 'descriptionIcon',
                        layout: 'form',
                        labelAlign: 'top',
                        border: false,
                        items: [{
                            style: 'margin-top: -4px; border 0px;',
                            labelSeparator: '',
                            xtype: 'textarea',
                            name: 'description',
                            hideLabel: true,
                            grow: false,
                            preventScrollbars: false,
                            anchor: '100% 100%',
                            emptyText: this.app.i18n._('Enter description'),
                            requiredGrant: 'editGrant'
                        }]
                    }),
                    new Tine.widgets.tags.TagPanel({
                        app: 'Filemanager',
                        border: false,
                        bodyStyle: 'border:1px solid #B5B8C8;'
                    })
                ]
            }]
        },
            new Tine.widgets.activities.ActivitiesTabPanel({
                app: this.appName,
                record_id: this.record.id,
                record_model: 'Tinebase_Model_Tree_Node'
            }),
            this.downloadLinkGrid,
            {xtype: 'Tine.Filemanager.UsagePanel', app: this.app, editDialog: this},
            grantsPanel
        ];

        if (_.get(fsConfig, 'enableNotifications', false) && this.record.data.type === 'folder') {
            var notificationPanel = new Tine.Filemanager.NotificationPanel({
                app: this.app,
                editDialog: this
            });
            items.push(notificationPanel)
        }

        return {
            xtype: 'tabpanel',
            plain:true,
            plugins: [{
                ptype : 'ux.tabpanelkeyplugin'
            }],
            activeTab: 0,
            border: false,
            items: items
        }
    }
});

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

    return window;
};


/***/ }),

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

/*
 * Tine 2.0
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Martin Jatho <m.jatho@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

__webpack_require__(178);
__webpack_require__(177);

/**
 * File grid panel
 *
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.NodeGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 *
 * <p>Node Grid Panel</p>
 * <p><pre>
 * </pre></p>
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Martin Jatho <m.jatho@metaways.de>
 * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)
 *
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Filemanager.FileGridPanel
 */
Tine.Filemanager.NodeGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
    /**
     * @cfg filesProperty
     * @type String
     */
    filesProperty: 'files',

    /**
     * config values
     * @private
     */
    header: false,
    border: false,
    deferredRender: false,
    autoExpandColumn: 'name',
    showProgress: true,
    enableDD: true,

    recordClass: Tine.Filemanager.Model.Node,
    listenMessageBus: true,
    hasDetailsPanel: false,
    evalGrants: true,
    // initialLoadAfterRender: false,

    /**
     * grid specific
     * @private
     */
    currentFolderNode: null,

    dataSafeAreaName: 'Tinebase.datasafe',
    dataSafeEnabled: false,

    /**
     * inits this cmp
     * @private
     */
    initComponent: function() {
        Ext.applyIf(this.defaultSortInfo, {field: 'name', direction: 'DESC'});
        Ext.applyIf(this.gridConfig, {
            autoExpandColumn: 'name',
            enableFileDialog: false,
            enableDragDrop: true,
            ddGroup: 'fileDDGroup',
            listeners: {
                scope: this,
                afterrender: this.initDragDrop
            }
        });

        if (this.readOnly || ! this.enableDD) {
            this.gridConfig.enableDragDrop = false;
        }

        this.dataSafeEnabled = Tine.Tinebase.areaLocks.hasLock(this.dataSafeAreaName);

        this.recordProxy = this.recordProxy || Tine.Filemanager.fileRecordBackend;

        this.gridConfig.cm = this.getColumnModel();

        this.defaultFilters = [
            {field: 'query', operator: 'contains', value: ''},
            {field: 'path', operator: 'equals', value: Tine.Tinebase.container.getMyFileNodePath()}
        ];

        this.plugins = this.plugins || [];

        this.filterToolbar = this.filterToolbar || this.getFilterToolbar();

        this.plugins.push(this.filterToolbar);

        if (!this.readOnly) {
            this.plugins.push({
                ptype: 'ux.browseplugin',
                multiple: true,
                scope: this,
                enableFileDialog: false,
                handler: this.onFilesSelect.createDelegate(this)
            });
        }

        if (this.hasQuickSearchFilterToolbarPlugin) {
            this.filterToolbar.getQuickFilterPlugin().criteriaIgnores.push({field: 'path'});
        }

        Tine.Filemanager.NodeGridPanel.superclass.initComponent.call(this);
        this.getStore().on('load', this.onLoad.createDelegate(this));

        // // cope with empty selections - dosn't work. It's confusing if e.g. the delte btn is enabled with no selections
        // this.selectionModel.on('selectionchange', function(sm) {
        //     if (sm.getSelections().length) {
        //         return;
        //     }
        //
        //     var _ = window.lodash,
        //         recordData = _.get(this, 'currentFolderNode.attributes'),
        //         record = recordData ? Tine.Tinebase.data.Record.setFromJson(JSON.stringify(recordData), this.recordClass) : null;
        //
        //     if (record) {
        //         this.actionUpdater.updateActions(record);
        //     }
        // }, this);
    },

    /**
     * after grid renderd
     */
    initDragDrop: function () {
        if (!this.enableDD) {
            return;
        }

        var grid = this.grid,
            view = grid.getView();

        view.dragZone.onBeforeDrag = this.onBeforeDrag.createDelegate(this);

        this.dropZone = new Ext.dd.DropZone(this.getEl(), {
            ddGroup: 'fileDDGroup',
            onNodeOver: this.onNodeOver.createDelegate(this),
            onNodeDrop: this.onNodeDrop.createDelegate(this),
            getTargetFromEvent: function(e) {
                var idx = view.findRowIndex(e.target),
                    record = grid.getStore().getAt(idx);

                return record;
            }
        })
    },

    /**
     * An empty function by default, but provided so that you can perform a custom action before the initial
     * drag event begins and optionally cancel it.
     * @param {Object} data An object containing arbitrary data to be shared with drop targets
     * @param {Event} e The event object
     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
     */
    onBeforeDrag: function(data, e) {
        var _ = window.lodash,
            // @TODO: rethink: do I need delte on the record or parent?
            requiredGrant = e.ctrlKey || e.altKey ? 'readGrant' : 'editGrant';

        return !this.selectionModel.isFilterSelect &&
            _.reduce(this.selectionModel.getSelections(), function(allowed, record) {
                return allowed && !! _.get(record, 'data.account_grants.' + requiredGrant);
            }, true);
    },

    /*
     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from {@link #getTargetFromEvent} for this node)
     * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
     * @param {Event} e The event
     * @param {Object} data An object containing arbitrary data supplied by the drag source
     * @return {String} status The CSS class that communicates the drop status back to the source so that the underlying {@link Ext.dd.StatusProxy} can be updated
     */
    onNodeOver: function(record, source, e, data) {
        var _ = window.lodash,
            dropAllowed =
                record.get('type') == 'folder'
                && _.get(record, 'data.account_grants.addGrant', false)
                && source == this.grid.getView().dragZone,
            action = e.ctrlKey || e.altKey ? 'copy' : 'move'

        return dropAllowed ?
            'tinebase-dd-drop-ok-' + action :
            Ext.dd.DropZone.prototype.dropNotAllowed;
    },

    /**
     * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped onto
     * the drop node.  The default implementation returns false, so it should be overridden to provide the
     * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
     * {@link #getTargetFromEvent} for this node)
     * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
     * @param {Event} e The event
     * @param {Object} data An object containing arbitrary data supplied by the drag source
     * @return {Boolean} True if the drop was valid, else false
     */
    onNodeDrop: function(target, dd, e, data) {
        Tine.Filemanager.fileRecordBackend.copyNodes(data.selections, target, !(e.ctrlKey || e.altKey));
        this.grid.getStore().remove(data.selections);
        return true;
    },

    /**
     * returns cm
     *
     * @return Ext.grid.ColumnModel
     * @private
     */
    getColumnModel: function(){
        var columns = [{
                id: 'tags',
                header: this.app.i18n._('Tags'),
                dataIndex: 'tags',
                width: 50,
                renderer: Tine.Tinebase.common.tagsRenderer,
                sortable: false,
                hidden: false
            }, {
                id: 'name',
                header: this.app.i18n._("Name"),
                width: 70,
                sortable: true,
                dataIndex: 'name',
                renderer: Ext.ux.PercentRendererWithName
            },{
                id: 'size',
                header: this.app.i18n._("Size"),
                width: 40,
                sortable: true,
                dataIndex: 'size',
                renderer: Tine.Tinebase.common.byteRenderer.createDelegate(this, [2, undefined], 3)
            },{
                id: 'contenttype',
                header: this.app.i18n._("Contenttype"),
                width: 50,
                sortable: true,
                dataIndex: 'contenttype',
                renderer: function(value, metadata, record) {

                    var app = Tine.Tinebase.appMgr.get('Filemanager');
                    if(record.data.type == 'folder') {
                        return app.i18n._("Folder");
                    }
                    else {
                        return value;
                    }
                }
            },{
                id: 'creation_time',
                header: this.app.i18n._("Creation Time"),
                width: 50,
                sortable: true,
                dataIndex: 'creation_time',
                renderer: Tine.Tinebase.common.dateTimeRenderer
            },{
                id: 'created_by',
                header: this.app.i18n._("Created By"),
                width: 50,
                sortable: true,
                dataIndex: 'created_by',
                renderer: Tine.Tinebase.common.usernameRenderer
            },{
                id: 'last_modified_time',
                header: this.app.i18n._("Last Modified Time"),
                width: 80,
                sortable: true,
                dataIndex: 'last_modified_time',
                renderer: Tine.Tinebase.common.dateTimeRenderer
            },{
                id: 'last_modified_by',
                header: this.app.i18n._("Last Modified By"),
                width: 50,
                sortable: true,
                dataIndex: 'last_modified_by',
                renderer: Tine.Tinebase.common.usernameRenderer
            }
        ];

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

        if (Tine.Tinebase.configManager.get('filesystem.index_content', 'Tinebase')) {
            columns.push({
                id: 'isIndexed',
                header: this.app.i18n._("Indexed"),
                tooltip: this.app.i18n._("File contents is part of the search index"),
                width: 40,
                sortable: true,
                dataIndex: 'isIndexed',
                hidden: true,
                renderer: function(value, i, node) {
                    return node.get('type') == 'file' ? Tine.Tinebase.common.booleanRenderer(value) : '';
                }
            });
        }

        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: columns
        });
    },

    /**
     * status column renderer
     * @param {string} value
     * @return {string}
     */
    statusRenderer: function(value) {
        return this.app.i18n._hidden(value);
    },

    /**
     * Capture space to toggle document preview
     */
    onKeyDown: function(e) {
        Tine.Filemanager.NodeGridPanel.superclass.onKeyDown.apply(this, arguments);

        // Open preview on space if a node is selected and the node type equals file
        if (e.getKey() == e.SPACE) {
            this.action_preview.execute()
        }
    },

    /**
     * init ext grid panel
     * @private
     */
    initGrid: function() {
        Tine.Filemanager.NodeGridPanel.superclass.initGrid.call(this);

        if (this.usePagingToolbar) {
           this.initPagingToolbar();
        }
    },

    /**
     * inserts a quota Message when using old Browsers with html4upload
     */
    initPagingToolbar: function() {
        if(!this.pagingToolbar || !this.pagingToolbar.rendered) {
            this.initPagingToolbar.defer(50, this);
            return;
        }

        this.quotaBar = new Ext.Component({
            html: '&nbsp;',
            style: {
                marginTop: '3px',
                width: '100px',
                height: '16px'
            }
        });
        this.pagingToolbar.insert(12, new Ext.Toolbar.Separator());
        this.pagingToolbar.insert(12, this.quotaBar);
        this.pagingToolbar.doLayout();
    },

    /**
     * returns filter toolbar -> supress OR filters
     * @private
     */
    getFilterToolbar: function(config) {
        config = config || {};
        var plugins = [];

        if (this.hasQuickSearchFilterToolbarPlugin) {
            this.quickSearchFilterToolbarPlugin = new Tine.widgets.grid.FilterToolbarQuickFilterPlugin();
            plugins.push(this.quickSearchFilterToolbarPlugin);
        }

        return new Tine.widgets.grid.FilterToolbar(Ext.apply(config, {
            app: this.app,
            recordClass: this.recordClass,
            filterModels: this.recordClass.getFilterModel().concat(this.getCustomfieldFilters()),
            defaultFilter: 'query',
            filters: this.defaultFilters || [],
            plugins: plugins
        }));
    },

    /**
     * returns add action / test
     *
     * @return {Object} add action config
     */
    getAddAction: function () {
        return {
            requiredGrant: 'addGrant',
            actionType: 'add',
            text: this.app.i18n._('Upload'),
            handler: this.onFilesSelect,
            disabled: true,
            scope: this,
            plugins: [{
                ptype: 'ux.browseplugin',
                multiple: true,
                enableFileDrop: false,
                disable: true
            }],
            iconCls: 'action_add',
            actionUpdater: function(action) {
                var _ = window.lodash,
                    allowAdd = _.get(this, 'currentFolderNode.attributes.account_grants.addGrant', false),
                    isVirtual = false;

                try {
                    isVirtual = this.currentFolderNode.attributes.nodeRecord.isVirtual();
                } catch(e) {}

                action.setDisabled(!allowAdd || isVirtual);
            }.createDelegate(this)
        };
    },

    initLayout: function() {
        Tine.Filemanager.NodeGridPanel.superclass.initLayout.call(this);

        var northPanel = lodash.find(this.items, function (i) {
            return i.region == 'north'
        });

        northPanel.tbar = new Tine.Filemanager.RecursiveFilter({
            gridPanel: this,
            hidden: true
        });
    },

    /**
     * init actions with actionToolbar, contextMenu and actionUpdater
     * @private
     */
    initActions: function() {
        // generic node actions - work on selections grid/tree nodes
        this.action_createFolder = Tine.Filemanager.nodeActionsMgr.get('createFolder');
        this.action_editFile = Tine.Filemanager.nodeActionsMgr.get('edit');
        this.action_deleteRecord = Tine.Filemanager.nodeActionsMgr.get('delete');
        this.action_download = Tine.Filemanager.nodeActionsMgr.get('download');
        this.action_moveRecord = Tine.Filemanager.nodeActionsMgr.get('move');
        this.action_publish = Tine.Filemanager.nodeActionsMgr.get('publish');
        this.action_systemLink = Tine.Filemanager.nodeActionsMgr.get('systemLink');
        this.action_preview = Tine.Filemanager.nodeActionsMgr.get('preview', {
            initialApp: this.app,
            sm: this.grid.getSelectionModel()
        });

        if (this.dataSafeEnabled) {
            this.action_dataSafe = new Ext.Action({
                text: 'Open Data Safe', // _('Open Data Safe')
                iconCls: 'action_filemanager_data_safe_locked',
                scope: this,
                handler: this.onDataSafeToggle,
                enableToggle: true
            });

            postal.subscribe({
                channel: 'areaLocks',
                topic: this.dataSafeAreaName +'.*',
                callback: this.applyDataSafeState.createDelegate(this)
            });

            this.applyDataSafeState();
        }

        // grid only actions - work on node which is displayed (this.currentFolderNode)
        // @TODO: fixme - ux problems with filterselect / initialData
        this.action_upload = new Ext.Action(this.getAddAction());
        this.action_goUpFolder = new Ext.Action({
            allowMultiple: true,
            actionType: 'goUpFolder',
            text: this.app.i18n._('Folder Up'),
            handler: this.onLoadParentFolder,
            iconCls: 'action_filemanager_folder_up',
            disabled: true,
            scope: this,
            actionUpdater: function(action) {
                var _ = window.lodash,
                    path = _.get(this, 'currentFolderNode.attributes.path', false);

                action.setDisabled(path == '/');
            }.createDelegate(this)
        });

        var contextActions = [
            this.action_deleteRecord,
            'rename',
            this.action_moveRecord,
            this.action_download,
            'resume',
            'pause',
            this.action_editFile,
            this.action_publish,
            this.action_systemLink,
            this.action_preview
        ];

        this.contextMenu = Tine.Filemanager.nodeContextMenu.getMenu({
            nodeName: Tine.Filemanager.Model.Node.getRecordName(),
            actions: contextActions,
            scope: this,
            backend: 'Filemanager',
            backendModel: 'Node'
        }, [{
            ptype: 'ux.itemregistry',
            key: 'Filemanager-Node-GridPanel-ContextMenu'
        }]);

        this.folderContextMenu = Tine.Filemanager.nodeContextMenu.getMenu({
            nodeName: Tine.Filemanager.Model.Node.getContainerName(),
            actions: [this.action_deleteRecord, 'rename', this.action_moveRecord, this.action_editFile, this.action_publish, this.action_systemLink],
            scope: this,
            backend: 'Filemanager',
            backendModel: 'Node'
        });

        this.actionUpdater.addActions(this.contextMenu.items);
        this.actionUpdater.addActions(this.folderContextMenu.items);

        var actions = [
            this.action_upload,
            this.action_createFolder,
            this.action_goUpFolder,
            this.action_download,
            this.action_deleteRecord,
            this.action_editFile,
            this.action_publish,
            this.action_systemLink,
            this.action_preview
        ];

        this.actionUpdater.addActions(actions);
    },

    /**
     * fm specific delete handler
     */
    onDeleteRecords: function(btn, e) {
        this.action_deleteRecord.execute();
    },

    /**
     * go up one folder
     *
     * @param {Ext.Component} button
     * @param {Ext.EventObject} event
     */
    onLoadParentFolder: function(button, event) {
        var currentFolderNode = this.currentFolderNode;

        if(currentFolderNode && currentFolderNode.parentNode) {
            this.currentFolderNode = currentFolderNode.parentNode;
            currentFolderNode.parentNode.select();
        }
    },

    onDataSafeToggle: function(button, e) {
        button.toggle(!button.pressed);

        var me = this,
            promise = !button.pressed ?
                Tine.Tinebase.areaLocks.unlock(me.dataSafeAreaName) :
                Tine.Tinebase.areaLocks.lock(me.dataSafeAreaName);

        me.getEl().mask('some text');
        promise
            .finally(function() {
                me.getEl().unmask();
            })
    },

    applyDataSafeState: function() {
        var me = this;

        Tine.Tinebase.areaLocks.isLocked(me.dataSafeAreaName).then(function(isLocked) {
            // if state change -> reload
            if (isLocked == me.action_dataSafe.items[0].pressed) {
                me.loadGridData({
                    preserveCursor:     false,
                    preserveSelection:  false,
                    preserveScroller:   false
                });
            }

            var cls = isLocked ? 'removeClass' : 'addClass';
            me.action_dataSafe.each(function(btn) {btn[cls]('x-type-data-safe')});
            me.action_dataSafe.each(function(btn) {btn.toggle(!isLocked)});
            me.action_dataSafe.setText(isLocked ? me.app.i18n._('Open Data Safe') : me.app.i18n._('Close Data Safe'));
            me.action_dataSafe.setIconClass(isLocked ? 'action_filemanager_data_safe_locked' : 'action_filemanager_data_safe_unlocked')
        });
    },

    /**
     * returns view row class
     */
    getViewRowClass: function(record, index, rowParams, store) {
        var className = Tine.Filemanager.NodeGridPanel.superclass.getViewRowClass.apply(this, arguments);

        if (this.dataSafeEnabled && !!record.get('pin_protected_node')) {
            className += ' x-type-data-safe'
        }

        return className;
    },

    /**
     * get the right contextMenu
     */
    getContextMenu: function(grid, row, e) {
        var r = this.store.getAt(row),
            type = r ? r.get('type') : null;

        return type === 'folder' ? this.folderContextMenu : this.contextMenu;
    },

    /**
     * get action toolbar
     *
     * @return {Ext.Toolbar}
     */
    getActionToolbar: function() {
        if (! this.actionToolbar) {
            var items = [
                this.splitAddButton ?
                    Ext.apply(new Ext.SplitButton(this.action_upload), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top',
                        arrowAlign:'right',
                        menu: new Ext.menu.Menu({
                            items: [],
                            plugins: [{
                                ptype: 'ux.itemregistry',
                                key:   'Tine.widgets.grid.GridPanel.addButton'
                            }, {
                                ptype: 'ux.itemregistry',
                                key:   'Tinebase-MainContextMenu'
                            }]
                        })
                    }) :
                    Ext.apply(new Ext.Button(this.action_upload), {
                        scale: 'medium',
                        rowspan: 2,
                        iconAlign: 'top'
                    }),

                Ext.apply(new Ext.Button(this.action_editFile), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_deleteRecord), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_createFolder), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_goUpFolder), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_download), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_publish), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_systemLink), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }),
                Ext.apply(new Ext.Button(this.action_preview), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                })
            ];

            if (this.dataSafeEnabled) {
                items.push(Ext.apply(new Ext.Button(this.action_dataSafe), {
                    scale: 'medium',
                    rowspan: 2,
                    iconAlign: 'top'
                }));
            }

            this.actionToolbar = new Ext.Toolbar({
                defaults: {height: 55},
                items: [{
                    xtype: 'buttongroup',
                    layout: 'toolbar',
                    buttonAlign: 'left',
                    columns: 8,
                    defaults: {minWidth: 60},
                    plugins: [{
                        ptype: 'ux.itemregistry',
                        key:   this.app.appName + '-' + this.recordClass.prototype.modelName + '-GridPanel-ActionToolbar-leftbtngrp'
                    }],
                    items: items
                }, this.getActionToolbarItems()]
            });

            this.actionToolbar.on('resize', this.onActionToolbarResize, this, {buffer: 250});
            this.actionToolbar.on('show', this.onActionToolbarResize, this);

            if (this.filterToolbar && typeof this.filterToolbar.getQuickFilterField == 'function') {
                this.actionToolbar.add('->', this.filterToolbar.getQuickFilterField());
            }
        }

        return this.actionToolbar;
    },

    /**
     * grid row doubleclick handler
     *
     * @param {Tine.Filemanager.NodeGridPanel} grid
     * @param {} row record
     * @param {Ext.EventObjet} e
     */
    onRowDblClick: function (grid, row, e) {
        var rowRecord = grid.getStore().getAt(row),
            _ = window.lodash,
            prefs = this.app.getRegistry().get('preferences'),
            dbClickAction = Tine.Tinebase.configManager.get('downloadsAllowed') ? prefs.get('dbClickAction') : 'preview';

        if (prefs && dbClickAction === 'download' && rowRecord.data.type == 'file'
            && !this.readOnly && _.get(rowRecord, 'data.account_grants.downloadGrant', false)
        ) {
            Tine.Filemanager.downloadFile(rowRecord);
        } else if (prefs && dbClickAction === 'preview' && rowRecord.data.type == 'file'
            && !this.readOnly && _.get(rowRecord, 'data.account_grants.readGrant', false)
        ) {
            this.action_preview.execute();
        } else if (rowRecord.data.type == 'folder') {
            this.expandFolder(rowRecord);
        }
    },

    /**
     * expand folder node
     *
     * @param rowRecord
     */
    expandFolder: function(rowRecord) {
        var treePanel = this.treePanel || this.app.getMainScreen().getWestPanel().getContainerTreePanel();
        var currentFolderNode = treePanel.getNodeById(rowRecord.id);

        if (currentFolderNode) {
            currentFolderNode.select();
            currentFolderNode.expand();
            this.currentFolderNode = currentFolderNode;
        } else {
            // get   ftb path filter
            this.filterToolbar.filterStore.each(function (filter) {
                var field = filter.get('field');
                if (field === 'path') {
                    filter.set('value', '');
                    filter.set('value', rowRecord.data);
                    filter.formFields.value.setValue(rowRecord.get('path'));

                    this.filterToolbar.onFiltertrigger();
                    return false;
                }
            }, this);
        }
    },

    /**
     * on remove handler
     *
     * @param {} button
     * @param {} event
     */
    onRemove: function (button, event) {
        var selectedRows = this.selectionModel.getSelections();
        for (var i = 0; i < selectedRows.length; i += 1) {
            this.store.remove(selectedRows[i]);
            var upload = Tine.Tinebase.uploadManager.getUpload(selectedRows[i].get('uploadKey'));

            if (upload) {
                upload.setPaused(true);
            }
        }
    },

    /**
     * populate grid store
     *
     * @param {} record
     */
    loadRecord: function (record) {
        if (record && record.get(this.filesProperty)) {
            var files = record.get(this.filesProperty);
            for (var i = 0; i < files.length; i += 1) {
                var file = new Ext.ux.file.Upload.file(files[i]);
                file.set('status', 'complete');
                file.set('nodeRecord', new Tine.Filemanager.Model.Node(file.data));
                this.store.add(file);
            }
        }
    },

    /**
     * upload new file and add to store
     *
     * @param {ux.BrowsePlugin} fileSelector
     * @param {} e
     */
    onFilesSelect: function (fileSelector, event) {
        var app = Tine.Tinebase.appMgr.get('Filemanager'),
            grid = this,
            targetNode = grid.currentFolderNode,
            gridStore = grid.store,
            rowIndex = false,
            me = this,
            targetFolderPath = grid.currentFolderNode.attributes.path,
            addToGrid = true,
            nodeRecord = null;

        if(event && event.getTarget()) {
            rowIndex = grid.getView().findRowIndex(event.getTarget());
        }


        if(targetNode.attributes) {
            nodeRecord = targetNode.attributes.nodeRecord;
        }

        if(rowIndex !== false && rowIndex > -1) {
            var newTargetNode = gridStore.getAt(rowIndex);
            if(newTargetNode && newTargetNode.data.type == 'folder') {
                targetFolderPath = newTargetNode.data.path;
                addToGrid = false;
                nodeRecord = new Tine.Filemanager.Model.Node(newTargetNode.data);
            }
        }

        if(!nodeRecord.isDropFilesAllowed()) {
            Ext.MessageBox.alert(
                    i18n._('Upload Failed'),
                    app.i18n._('Putting files in this folder is not allowed!')
            ).setIcon(Ext.MessageBox.ERROR);

            return;
        }

        var files = fileSelector.getFileList();

        var filePathsArray = [], uploadKeyArray = [], promises = [];

        Ext.each(files, function (file) {
            var promise = new Promise(function (fullfill, reject) {
                me.isFile(file).then(function () {
                    var fileRecord = Tine.Filemanager.Model.Node.createFromFile(file),
                        filePath = targetFolderPath + '/' + fileRecord.get('name');

                    fileRecord.set('path', filePath);
                    var existingRecordIdx = gridStore.find('name', fileRecord.get('name'));
                    if (existingRecordIdx < 0) {
                        gridStore.add(fileRecord);
                    }

                    var upload = new Ext.ux.file.Upload({
                        fmDirector: grid,
                        file: file,
                        fileSelector: fileSelector,
                        id: filePath
                    });

                    filePathsArray.push(filePath);
                    uploadKeyArray.push(Tine.Tinebase.uploadManager.queueUpload(upload));
                }, me).then(function () {
                    fullfill();
                }).catch(function() {
                    fullfill();
                });
            });
            promises.push(promise);
        });

        Promise.all(promises).then(function () {
            if (0 === uploadKeyArray.length) {
                return;
            }

            var params = {
                filenames: filePathsArray,
                type: "file",
                tempFileIds: [],
                forceOverwrite: false
            };
            Tine.Filemanager.fileRecordBackend.createNodes(params, uploadKeyArray, true);
        });
    },

    isFile: function (file) {
        return Promise.resolve();
        // NOTE: fileReader can't cope with files ~> 1GB
        //       with html5-file-selector we can't have directories here
        // return new Promise(function (resolve, reject) {
        //     var fr = new FileReader();
        //     fr.onload = function () {
        //         if (fr.result === null) {
        //             reject();
        //         } else {
        //             resolve();
        //         }
        //     };
        //     fr.readAsText(file);
        // });
    },

    /**
     * grid on load handler
     *
     * @param grid
     * @param records
     * @param options
     */
    onLoad: function(store, records, options){
        var _ = window.lodash,
            quota = _.get(store, 'reader.jsonData.quota', false),
            grid = this;

        for(var i=records.length-1; i>=0; i--) {
            var record = records[i];
            if(record.get('type') == 'file' && (!record.get('size') || record.get('size') == 0)) {
                var upload = Tine.Tinebase.uploadManager.getUpload(record.get('path'));

                if(upload) {
                      if(upload.fileRecord && record.get('name') == upload.fileRecord.get('name')) {
                          grid.updateNodeRecord(record, upload.fileRecord);
                          record.afterEdit();
                    }
                }
            }
        }

        if (quota) {
            var qhtml = Tine.widgets.grid.QuotaRenderer(quota.effectiveUsage, quota.effectiveQuota, /*use SoftQuota*/ true);
            this.quotaBar.show();
            if (this.quotaBar.rendered) {
                this.quotaBar.update(qhtml);
            } else {
                this.quotaBar.html = qhtml;
            }
        } else {
            this.quotaBar.hide();
        }
    },

    /**
     * update grid nodeRecord with fileRecord data
     *
     * @param nodeRecord
     * @param fileRecord
     */
    updateNodeRecord: function(nodeRecord, fileRecord) {
        for(var field in fileRecord.fields) {
            nodeRecord.set(field, fileRecord.get(field));
        }
        nodeRecord.fileRecord = fileRecord;
    }
});


/***/ }),

/***/ 638:
/***/ (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) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
 * 
 * TODO         maybe we don't need this
 */
Ext.ns('Tine.Filemanager');

/**
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.DownloadLinkDialog
 * @extends     Tine.widgets.dialog.EditDialog
 * 
 * <p>Sieve Filter Dialog</p>
 * <p>This dialog is for editing sieve filters (rules).</p>
 * <p>
 * </p>
 * 
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * 
 * @param       {Object} config
 * @constructor
 * Create a new RulesDialog
 */
Tine.Filemanager.DownloadLinkDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {

    /**
     * @cfg {Tine.Felamimail.Model.Account}
     * 
     * TODO use node record?
     */
    node: null,

    /**
     * @private
     */
    windowNamePrefix: 'DownloadLinkWindow_',
    appName: 'Filemanager',
//    loadRecord: false,
    mode: 'local',
    tbarItems: [],
    evalGrants: false,
    
    //private
    initComponent: function(){
        Tine.Filemanager.DownloadLinkDialog.superclass.initComponent.call(this);
        
        this.i18nRecordName = this.app.i18n._('Node Download Links');
    },
    
    /**
     * overwrite update toolbars function (we don't have record grants yet)
     * 
     * @private
     */
    updateToolbars: Ext.emptyFn,
    
    /**
     * init record to edit
     * -> we don't have a real record here
     */
    initRecord: function() {
//        this.onRecordLoad();
    },
    
    /**
     * executed after record got updated from proxy
     * -> we don't have a real record here
     * 
     * @private
     */
    onRecordLoad: function() {
    },
        
    /**
     * returns dialog
     * 
     * NOTE: when this method gets called, all initalisation is done.
     * 
     * @return {Object}
     * @private
     * 
     */
    getFormItems: function() {
        this.linkGrid = new Tine.Filemanager.DownloadLinkGridPanel({
            //account: this.account
        });
        
        return [this.linkGrid];
    }
});

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


/***/ }),

/***/ 639:
/***/ (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) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

/**
 * File grid panel
 * 
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.DownloadLinkGridPanel
 * @extends     Tine.widgets.grid.GridPanel
 * 
 * <p>DownloadLink Grid Panel</p>
 * <p><pre>
 * </pre></p>
 * 
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Philipp Schüle <p.schuele@metaways.de>
 * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
 * 
 * @param       {Object} config
 * @constructor
 * Create a new Tine.Filemanager.FileGridPanel
 */
Tine.Filemanager.DownloadLinkGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {
    /* config */
    frame: true,
    border: true,
    autoScroll: true,
    layout: 'fit',
    autoExpandColumn: 'url',
    
    enableHdMenu: false,
    /**
     * inits this cmp
     * @private
     */
    initComponent: function() {
        var _ = window.lodash,
            record = this.editDialog.record,
            evalGrants = this.editDialog.evalGrants,
            hasRequiredGrant = !evalGrants || _.get(record, record.constructor.getMeta('grantsPath') + '.' + this.requiredGrant);

        this.recordProxy = Tine.Filemanager.downloadLinkRecordBackend;
        this.recordClass = Tine.Filemanager.Model.DownloadLink;
        
        this.store = new Ext.data.Store({
            fields: this.recordClass,
            proxy: this.recordProxy,
            reader: this.recordProxy.getReader(),
            remoteSort: false,
            sortInfo: {
                field: 'expiry_time',
                direction: 'DESC'
            },
            listeners: {
                scope: this,
                'beforeload': this.onStoreBeforeload,
                'update': this.onStoreUpdate
            }
        });
        
        this.actionCreate = new Ext.Action({
            text: this.app.i18n._('Create Public Link'),
            disabled: !hasRequiredGrant,
            scope: this,
            handler: this.onCreate,
            iconCls: 'action_add'
        });
        
        this.actionRemove = new Ext.Action({
            text: i18n._('Remove record'),
            disabled: !hasRequiredGrant,
            scope: this,
            handler: this.onRemove,
            iconCls: 'action_delete'
        });
        
        this.tbar = [
            this.actionCreate,
            this.actionRemove
        ];
        
        this.contextMenu = new Ext.menu.Menu({
            plugins: [{
                ptype: 'ux.itemregistry',
                key:   'Tinebase-MainContextMenu'
            }],
            items: [
                this.actionCreate,
                this.actionRemove
            ]
        });
        
        this.cm = this.getColumnModel();
        this.sm = new Ext.grid.RowSelectionModel({multiSelect:true});

        this.plugins = this.plugins ? this.plugins : [];
        this.plugins.push(new Ext.ux.grid.GridViewMenuPlugin({}));
        this.stripeRows = Tine.Tinebase.registry.get('preferences').get('gridStripeRows')
            ? Tine.Tinebase.registry.get('preferences').get('gridStripeRows')
            : false,
        
        // on selectionchange handler
        this.sm.on('selectionchange', function(sm) {
            var rowCount = sm.getCount();
            this.actionRemove.setDisabled(rowCount == 0);
        }, this);
        
        // on rowcontextmenu handler
        this.on('rowcontextmenu', this.onRowContextMenu.createDelegate(this), this);
        
        Tine.Filemanager.DownloadLinkGridPanel.superclass.initComponent.call(this);
        
        this.initialLoad();
    },
    
    /**
     * that's the context menu handler
     * @param {} grid
     * @param {} row
     * @param {} e
     */
    onRowContextMenu: function(grid, row, e) {
        e.stopEvent();
        
        this.fireEvent('beforecontextmenu', grid, row, e);
        
        var sm = grid.getSelectionModel();
        if (!sm.isSelected(row)) {
            sm.selectRow(row);
        }
        
        this.contextMenu.showAt(e.getXY());
    },
    
    onCreate: function() {
        if (! this.createMask) {
            this.createMask = new Ext.LoadMask(this.getEl(), {
                msg: this.app.i18n._('Creating new Download Link...')
            });
        }
        this.createMask.show();
        
        var date = new Date();
        date.setDate(date.getDate() + 30);
        
        var record = new this.recordClass({node_id: this.editDialog.record.get('id'), expiry_time: date});
        this.recordProxy.saveRecord(record, {success: this.onAfterCreate, scope: this});
    },
    
    onAfterCreate: function() {
        this.store.load();
        this.createMask.hide();
    },
    
    onAfterDelete: function() {
        this.store.load();
        this.deleteMask.hide();
    },
    
    /**
     * remove handler
     * 
     * @param {} button
     * @param {} event
     */
    onRemove: function(button, event) {
        
        var selectedRows = this.getSelectionModel().getSelections();
        
        if (selectedRows.length == 0) {
            return;
        }
        
        if (! this.deleteMask) {
            this.deleteMask = new Ext.LoadMask(this.getEl(), {
                msg: selectedRows.length > 1 ? this.app.i18n._('Deleting Download Links...') : this.app.i18n._('Deleting Download Link...')
            });
        }
        
        this.deleteMask.show();
        
        this.recordProxy.deleteRecords(selectedRows, {success: this.onAfterDelete, scope: this});
    },
    
    /**
     * called before store queries for data
     */
    onStoreBeforeload: function(store, options) {
        options.params = options.params || {};
        // allways start with an empty filter set!
        // this is important for paging and sort header!
        options.params.filter = [{field: 'node_id', operator: 'in', value: this.editDialog.record.get('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) {
        switch (operation) {
            case Ext.data.Record.EDIT:
                // don't save these records. Add them to the parents' record store
                this.recordProxy.saveRecord(record, {
                    scope: this,
                    success: function(updatedRecord) {
                        store.commitChanges();

                        // update record in store to prevent concurrency problems
                        record.data = updatedRecord.data;
                    }
                });
                break;
            case Ext.data.Record.COMMIT:
                //nothing to do, as we need to reload the store anyway.
                break;
        }
    },
    
    /**
     * returns cm
     * 
     * @return Ext.grid.ColumnModel
     * @private
     * 
     * TODO    add more columns
     */
    getColumnModel: function(){
        var columns = [{ 
                id: 'url',
                header: this.app.i18n._('Url'),
                dataIndex: 'url',
                width: 250,
                //sortable: false,
                hidden: false,
                editor: new Ext.form.Field({
                    listeners: {
                        change: function() {
                            this.setValue(this.startValue);
                        }
                    }
                }),
                readOnly: true,
                disabled: true
            }, {
                id: 'created_by',
                header: this.app.i18n._("Created By"),
                width: 150,
                sortable: true,
                dataIndex: 'created_by',
                hidden: false,
                renderer: Tine.Tinebase.common.usernameRenderer
            }, {
                id: 'creation_time',
                header: this.app.i18n._("Creation Time"),
                width: 100,
                sortable: true,
                dataIndex: 'creation_time',
                renderer: Tine.Tinebase.common.dateTimeRenderer,
                hidden: true
            }, {
                id: 'expiry_time',
                header: this.app.i18n._("Expiration Time"),
                width: 100,
                sortable: true,
                dataIndex: 'expiry_time',
                hidden: false,
                renderer: Tine.Tinebase.common.dateTimeRenderer,
                editor: new Ext.ux.form.ClearableDateField()
            }, {
                id: 'access_count',
                header: this.app.i18n._("Access Count"),
                width: 70,
                sortable: true,
                dataIndex: 'access_count',
                hidden: false
            }, {
                id: 'last_modified_time',
                header: this.app.i18n._("Last Modified Time"),
                width: 100,
                sortable: true,
                dataIndex: 'last_modified_time',
                hidden: true,
                renderer: Tine.Tinebase.common.dateTimeRenderer
            }, {
                id: 'last_modified_by',
                header: this.app.i18n._("Last Modified By"),
                width: 150,
                sortable: true,
                dataIndex: 'last_modified_by',
                hidden: true,
                renderer: Tine.Tinebase.common.usernameRenderer 
            }
        ];
        
        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: columns
        });
    },
    
    /**
     * preform the initial load of grid data
     */
    initialLoad: function() {
        this.store.load.defer(10, this.store);
    }
});


/***/ }),

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

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

Ext.ns('Tine.Filemanager');

/**
 * @namespace Tine.Filemanager
 * @class Tine.Filemanager.Application
 * @extends Tine.Tinebase.Application
 */
Tine.Filemanager.Application = Ext.extend(Tine.Tinebase.Application, {
    /**
     * Get translated application title of this application
     *
     * @return {String}
     */
    getTitle : function() {
        return this.i18n.gettext('Filemanager');
    },

    routes: {
        'showNode(.*)': 'showNode'
    },

    /**
     * display file/directory in mainscreen
     * /#/Filemanager/showNode/shared/someFolder/someFile
     */
    showNode: function(path) {
        this.getMainScreen().getCenterPanel().initialLoadAfterRender = false;
        Tine.Tinebase.MainScreenPanel.show(this);
        // NOTE: decodeURIComponent can't cope with +
        path = Ext.ux.util.urlCoder.decodeURIComponent(path);

        // if file, show directory file is in
        var dirPath = path;
        if (String(path).match(/\/.*\..+$/)) {
            var pathParts = path.split('/');
            pathParts.pop();
            dirPath = pathParts.join('/');
        }

        (function() {
            var cp = this.getMainScreen().getCenterPanel(),
                grid = cp.getGrid(),
                store = cp.getStore(),
                ftb = cp.filterToolbar,
                highlight = function() {
                    store.un('load', highlight);
                    var sm = grid.getSelectionModel(),
                        idx = store.find('path', path);
                    if (idx) {
                        sm.selectRow(idx);
                    }
                };

            store.on('load', highlight);
            ftb.setValue([{field: 'path', operator: 'equals', value: dirPath}]);
            ftb.onFiltertrigger();
        }).defer(500, this);
    }
});

/*
 * register additional action for genericpickergridpanel
 */
Tine.widgets.relation.MenuItemManager.register('Filemanager', 'Node', {
    text: 'Save locally',   // i18n._('Save locally')
    iconCls: 'action_filemanager_save_all',
    requiredGrant: 'readGrant',
    actionType: 'download',
    allowMultiple: false,
    handler: function(action) {
        var node = action.grid.store.getAt(action.gridIndex).get('related_record');
        Tine.Filemanager.downloadFile(node);
    }
});

/**
 * @namespace Tine.Filemanager
 * @class Tine.Filemanager.MainScreen
 * @extends Tine.widgets.MainScreen
 */
Tine.Filemanager.MainScreen = Ext.extend(Tine.widgets.MainScreen, {
    activeContentType: 'Node'
});

/**
 * download file into browser
 *
 * @param {String|Tine.Filemanager.Model.Node}
 * @param revision
 * @param appName
 * @returns {Ext.ux.file.Download}
 *
 * @todo move to Tine.Filemanager.FileRecordBackend
 */
Tine.Filemanager.downloadFile = function(path, revision, appName) {
    var _ = window.lodash;
    appName = appName || 'Filemanager';
    path = _.get(path, 'data.path') || _.get(path, 'path') || path;

    return new Ext.ux.file.Download({
        params: {
            method: appName + '.downloadFile',
            requestType: 'HTTP',
            id: '',
            path: path,
            revision: revision
        }
    }).start();
};


/**
 * download file into browser with base64 (btoa) encoded path
 *
 * @param {String} encodedpath
 * @param revision
 * @param appName
 * @returns {Ext.ux.file.Download}
 *
 * @refactor: we should only need one downloadFile fn
 */
Tine.Filemanager.downloadFileByEncodedPath = function(encodedpath, revision, appName) {
    return Tine.Filemanager.downloadFile(atob(encodedpath), revision, appName);
};


/***/ }),

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

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

/**
 * File picker dialog
 *
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.FilePickerDialog
 * @extends     Tine.Tinebase.dialog.Dialog
 * @constructor
 * @param       {Object} config The configuration options.
 */
Tine.Filemanager.FilePickerDialog = Ext.extend(Tine.Tinebase.dialog.Dialog, {
    layout: 'fit',

    /**
     * Dialog window
     */
    window: null,

    /**
     * The validated and chosen node
     */
    nodes: null,

    /**
     * Allow to select one or more node
     */
    singleSelect: true,

    /**
     * A constraint allows to alter the selection behaviour of the picker, for example only allow to select files.
     *
     * By default, file and folder are allowed to be selected, the concrete implementation needs to define it's purpose
     *
     * Valids constraints:
     *  - file
     *  - folder
     *  - null (take all)
     */
    constraint: null,

    /**
     * @cfg {Array} requiredGrants
     * grants which are required to select nodes
     */
    requiredGrants: ['readGrant'],

    windowNamePrefix: 'FilePickerDialog_',

    /**
     * Constructor.
     */
    initComponent: function () {
        this.addEvents(
            /**
             * If the dialog will close and an valid node was selected
             * @param node
             */
            'selected'
        );

        this.items = [{
            layout: 'fit',
            items: [
                this.getFilePicker()
            ]
        }];

        this.on('apply', function() {
            this.fireEvent('selected', this.nodes);
        }, this);

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

        if (! this.windowTitle) {
            switch(this.constraint) {
                case 'file':
                    this.windowTitle = this.singleSelect ? this.app.i18n._('Select a file') : this.app.i18n._('Select files');
                    break;
                case 'folder':
                    this.windowTitle = this.singleSelect ? this.app.i18n._('Select a folder') : this.app.i18n._('Select folders');
                    break;
                default:
                    this.windowTitle = this.singleSelect ? this.app.i18n._('Select an item') : this.app.i18n._('Select items');
                    break;
            }
        }

        this.windowTitle = this.windowTitle || this.app.i18n._('')
        Tine.Filemanager.FilePickerDialog.superclass.initComponent.call(this);
    },

    getEventData: function () {
        return this.nodes;
    },

    /**
     * Create a new filepicker and register listener
     * @returns {*}
     */
    getFilePicker: function () {
        var picker = new Tine.Filemanager.FilePicker({
            requiredGrants: this.requiredGrants,
            constraint: this.constraint,
            singleSelect: this.singleSelect
        });

        picker.on('nodeSelected', this.onNodesSelected.createDelegate(this));
        picker.on('invalidNodeSelected', this.onInvalidNodesSelected.createDelegate(this));

        return picker;
    },

    /**
     * If a node was selected
     * @param nodes
     */
    onNodesSelected: function (nodes) {
        this.nodes = nodes;
        this.buttonApply.setDisabled(false);
    },

    afterRender: function () {
        Tine.Filemanager.FilePickerDialog.superclass.afterRender.apply(this, arguments);
        this.buttonApply.setDisabled(true);
    },
    
    /**
     * If an invalid node was selected
     */
    onInvalidNodesSelected: function () {
        this.buttonApply.setDisabled(true);
    },

    /**
     * Creates a new pop up dialog/window (acc. configuration)
     *
     * @returns {null}
     */
    openWindow: function () {
        this.window = Tine.WindowFactory.getWindow({
            title: this.windowTitle,
            closeAction: 'close',
            modal: true,
            width: 550,
            height: 500,
            layout: 'fit',
            plain: true,
            items: [
                this
            ]
        });

        return this.window;
    }
});


/***/ }),

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

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

/**
 * FilePicker component.
 *
 * Standalone file picker for selecting a node or a folder from filemanager.
 * The filepicker does require the filemanager to be enabled!
 *
 * The filepicker offers two events:
 *  - nodeSelected
 *  - invalidNodeSelected
 */
Tine.Filemanager.FilePicker = Ext.extend(Ext.Container, {
    /**
     * Filemanager app
     * @private
     */
    app: null,

    /**
     * Layout.
     * @private
     */
    layout: 'fit',

    /**
     * NodeTreePanel instance
     * @private
     */
    treePanel: null,

    /**
     * NodeGridPanel instance
     * @private
     */
    gridPanel: null,

    /**
     * Selected nodes
     * @private
     */
    selection: [],

    /**
     * Last clicked node
     * @private
     */
    lastClickedNode: null,

    /**
     * Allow to select one or more node
     */
    singleSelect: true,

    /**
     * A constraint allows to alter the selection behaviour of the picker, for example only allow to select files.
     *
     * By default, file and folder are allowed to be selected, the concrete implementation needs to define it's purpose
     *
     * Valids constraints:
     *  - file
     *  - folder
     *  - null (take all)
     */
    constraint: null,

    /**
     * @cfg {Array} requiredGrants
     * grants which are required to select nodes
     */
    requiredGrants: ['readGrant'],

    /**
     * Constructor.
     */
    initComponent: function () {
        var model = Tine.Filemanager.Model.Node;
        this.app = Tine.Tinebase.appMgr.get(model.getMeta('appName'));

        this.treePanel = this.getTreePanel();
        this.gridPanel = this.getGridPanel();

        this.addEvents(
            /**
             * Fires when a file was selected which fulfills all constraints
             *
             * @param nodeData selected node data
             */
            'nodeSelected',
            /**
             * Fires if a node is selected which does not fulfill the provided constraints
             */
            'invalidNodeSelected'
        );

        this.items = [{
            layout: 'border',
            border: false,
            frame: false,
            items: [{
                layout: 'fit',
                region: 'west',
                frame: false,
                width: 200,
                border: false,
                split: true,
                collapsible: true,
                header: false,
                collapseMode: 'mini',
                items: [
                    this.treePanel
                ]
            }, {
                layout: 'fit',
                split: true,
                frame: false,
                border: false,
                region: 'center',
                width: 300,
                items: [
                    this.gridPanel
                ]
            }]
        }];

        Tine.Filemanager.FilePicker.superclass.initComponent.call(this);
    },

    /**
     * Updates selected element and triggers an event
     */
    updateSelection: function (nodes) {
        // If selection doesn't fullfil constraint, we don't throw a selectionChange event
        if (!this.checkConstraint(nodes)) {
            this.fireEvent('invalidNodeSelected');
            return false;
        }

        //  Clear previous selection
        this.selection = [];

        var me = this;
        Ext.each(nodes, function (node) {
            me.selection.push(node.data || node);
        });

        this.fireEvent('nodeSelected', this.selection);
    },

    /**
     * @returns {Tine.Filemanager.NodeTreePanel}
     */
    getTreePanel: function () {
        if (this.treePanel) {
            return this.treePanel;
        }

        var me = this;
        var treePanel = new Tine.Filemanager.NodeTreePanel({
            height: 200,
            width: 200,
            readOnly: true,
            filterMode: 'filterToolbar',
            // fixme: NodeTreePanel fetches grid via app registry
            onSelectionChange: Tine.widgets.container.TreePanel.prototype.onSelectionChange
        });

        treePanel.getSelectionModel().on('selectionchange', function (selectionModel) {
            var treeNode = selectionModel.getSelectedNode();
            me.updateSelection([
                treeNode.attributes
            ]);
        });

        return treePanel;
    },

    /**
     * @returns {*}
     */
    getGridPanel: function () {
        if (this.gridPanel) {
            return this.gridPanel;
        }

        var me = this;

        var gridPanel = new Tine.Filemanager.NodeGridPanel({
            app: me.app,
            height: 200,
            width: 200,
            border: false,
            frame: false,
            readOnly: true,
            enableDD: false,
            enableDrag: false,
            treePanel: this.getTreePanel(),
            hasQuickSearchFilterToolbarPlugin: false,
            stateIdSuffix: '-FilePicker',
            plugins: [this.getTreePanel().getFilterPlugin()]
        });

        gridPanel.getGrid().reconfigure(gridPanel.getStore(), this.getColumnModel());
        gridPanel.getGrid().getSelectionModel().singleSelect = this.singleSelect;
        gridPanel.getGrid().getSelectionModel().on('rowselect', function (selModel) {
            var record = selModel.getSelections();
            me.updateSelection(record);
        });

        // Hide filter toolbar
        gridPanel.filterToolbar.hide();

        return gridPanel;
    },

    /**
     * Check if selection fits current constraint
     * @returns {boolean}
     */
    checkConstraint: function (nodes) {
        var me = this;
        var valid = true;

        Ext.each(nodes, function (node) {
            node = node.data ? node : new Tine.Filemanager.Model.Node(node);
            if (!me.checkNodeConstraint(node)) {
                valid = false;
                return false;
            }
        });

        return valid;
    },

    /**
     * Checks if a single node matches the constraints
     *
     * @param node
     * @returns {boolean}
     */
    checkNodeConstraint: function (node) {
        // Minimum information to proceed here
        if (!node.get('path') || !node.id) {
            return false;
        }

        if (! this.hasGrant(node, this.requiredGrants)) {
            return false;
        }

        // If no constraints apply, skip here
        if (this.constraint === null) {
            return true;
        }

        return node.get('type') == this.constraint;
    },

    /**
     * checkes if user has requested grant for given node
     *
     * @param {Tine.Filemanager.Model.Node} node
     * @param {Array} grant
     * @return bool
     */
    hasGrant: function(node, grants) {
        var _ = window.lodash,
            condition = true;

        _.each(grants, function(grant) {
            condition = condition && _.get(node, 'data.account_grants.' + grant, false);
            if (grant == 'addGrant' && node.isVirtual()) {
                condition = false;
            }
        });

        return condition;
    },


    /**
     * Customized column model for the grid
     * @returns {*}
     */
    getColumnModel: function () {
        var columns = [{
            id: 'name',
            header: this.app.i18n._("Name"),
            width: 70,
            sortable: true,
            dataIndex: 'name',
            renderer: Ext.ux.PercentRendererWithName
        }, {
            id: 'size',
            header: this.app.i18n._("Size"),
            width: 40,
            sortable: true,
            dataIndex: 'size',
            renderer: Tine.Tinebase.common.byteRenderer.createDelegate(this, [2, true], 3)
        }, {
            id: 'contenttype',
            header: this.app.i18n._("Contenttype"),
            width: 50,
            sortable: true,
            dataIndex: 'contenttype',
            renderer: function (value, metadata, record) {

                var app = Tine.Tinebase.appMgr.get('Filemanager');
                if (record.data.type == 'folder') {
                    return app.i18n._("Folder");
                }
                else {
                    return value;
                }
            }
        }];

        return new Ext.grid.ColumnModel({
            defaults: {
                sortable: true,
                resizable: true
            },
            columns: columns
        });
    }
});


/***/ }),

/***/ 643:
/***/ (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) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

/**
 * Recursive Filter
 *
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.RecursiveFilter
 * @extends     Ext.Toolbar
 *
 * @param       {Object} config
 * @constructor
 */
Tine.Filemanager.RecursiveFilter = Ext.extend(Ext.Toolbar, {

    /**
     * @cfg {Tine.widgets.grid.GridPanel}
     */
    gridPanel: null,

    field: 'recursive',
    operator: 'equals',
    style: 'background-image: none;',

    initComponent: function() {
        this.app = Tine.Tinebase.appMgr.get('Filemanager');

        Ext.applyIf(this, new Tine.widgets.grid.FilterPlugin());
        this.init(this.gridPanel);

        this.globalBtn = new Ext.Button({
            text: this.app.i18n._('Whole Filemanager'),
            pressed: false,
            ref: '../globalBtn',
            xtype: 'tbbtnlockedtoggle',
            toggleGroup: 'Calendar_Toolbar_tgViewTypes',
            handler: this.onFilterChange,
            scope: this
        });

        this.localBtn = new Ext.Button({
            text: this.app.i18n._('This Folder'),
            pressed: true,
            ref: '../localBtn',
            xtype: 'tbbtnlockedtoggle',
            toggleGroup: 'Calendar_Toolbar_tgViewTypes',
            handler: this.onFilterChange,
            scope: this
        });

        this.items = [{
            xtype: 'tbtext',
            text: this.app.i18n._('Search') + ': '
        }, this.globalBtn, this.localBtn];

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

    getValue: function() {
        return this.globalBtn.pressed ?
            {field: this.field, operator: this.operator, value: true} : null;
    },

    setValue: function(filters) {
        // only show if we have a contributing filter
        var setVisible = false;

        for (var i=0; i<filters.length; i++) {
            switch (filters[i].field) {
                case 'query':
                    setVisible |= !!filters[i].value;
                    break;
                case 'type':
                case 'path':
                    break;
                case 'recursive':
                    this.globalBtn.toggle(!!filters[i].value);
                    this.localBtn.toggle(!filters[i].value);
                    break;
                default:
                    setVisible |= true;
                    break;
            }
        }

        this.setVisible(setVisible);

        if (! setVisible) {
            // reset own filter
            this.globalBtn.toggle(false);
            this.localBtn.toggle(true);
        }
    }
});

/***/ }),

/***/ 644:
/***/ (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) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

/**
 * @namespace   Tine.Filemanager
 * @class       Tine.Filemanager.UsagePanel
 * @extends     Ext.Panel
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Cornelius Weiß <c.weiss@metaways.de>
 *
 * @param       {Object} config
 * @constructor
 */
Tine.Filemanager.UsagePanel = Ext.extend(Ext.Panel, {

    layout: 'fit',
    border: false,
    requiredGrant: 'adminGrant',

    initComponent: function() {
        this.app = this.app || Tine.Tinebase.appMgr.get('Filemanager');
        this.title = this.app.i18n._('Usage');

        this.editDialog.on('load', this.onRecordLoad, this);
        this.editDialog.on('recordUpdate', this.onRecordUpdate, this);

        var _ = window.lodash,
            fsConfig = Tine.Tinebase.configManager.get('quota'),
            showQuotaUi = _.get(fsConfig, 'showUI', true),
            bytesRenderer = Tine.Tinebase.common.byteRenderer.createDelegate(this, [2, undefined], 3),
            columns = [
                {header: this.app.i18n._('Size'), width: 150, sortable: true, renderer: bytesRenderer, dataIndex: 'size'}
            ];

        this.hasOwnQuotaCheckbox = new Ext.form.Checkbox({
            hidden: !showQuotaUi,
            disabled: true,
            boxLabel: this.app.i18n._('This folder has own quota'),
            listeners: {scope: this, check: this.onOwnQuotaCheck}
        });
        this.quotaField = Ext.ComponentMgr.create({
            hidden: !showQuotaUi,
            fieldLabel: this.app.i18n.gettext('Quota'),
            emptyText: this.app.i18n.gettext('no quota set'),
            name: 'quota',
            xtype: 'extuxbytesfield'
        });
        this.effetiveUsageField = Ext.ComponentMgr.create({
            fieldLabel: this.app.i18n.gettext('Current Usage'),
            name: 'effectiveQuota',
            xtype: 'displayfield'
        });

        this.hasOwnQuotaDescription = new Ext.form.Label({
            hidden: !showQuotaUi,
            columnWidth: 1,
            text: this.app.i18n._("The Quota applies recursively for files and subfolders. Please note, the Effective Quota differs wehn a parent folder has set a lower quota.")
        });

        this.byTypeStore = new Ext.data.ArrayStore({
            fields: [
                {name: 'type'},
                {name: 'size', type: 'int'},
                {name: 'revision_size', type: 'int'}
            ]
        });

        this.byUserStore = new Ext.data.ArrayStore({
            fields: [
                {name: 'user'},
                {name: 'size', type: 'int'},
                {name: 'revision_size', type: 'int'}
            ]
        });

        if (Tine.Tinebase.configManager.get('filesystem.modLogActive', 'Tinebase')) {
            columns.push({header: this.app.i18n._('Revision Size'), width: 150, sortable: true, renderer: bytesRenderer, dataIndex: 'revision_size'});
        }

        this.byTypeGrid = new Ext.grid.GridPanel({
            store: this.byTypeStore,
            flex: 1,
            columns: [
                {id:'type',header: this.app.i18n._('File Type'), width: 160, sortable: true, dataIndex: 'type'},
            ].concat(columns),
            stripeRows: true,
            autoExpandColumn: 'type',
            title: this.app.i18n._('Usage by File Type'),
            // baseCls: 'ux-arrowcollapse'
        });

        this.byUserGrid = new Ext.grid.GridPanel({
            store: this.byUserStore,
            flex: 1,
            columns: [
                {id:'user',header: this.app.i18n._('User'), width: 160, sortable: true, dataIndex: 'user'},
            ].concat(columns),
            stripeRows: true,
            autoExpandColumn: 'user',
            title: this.app.i18n._('Usage by User'),
            // baseCls: 'ux-arrowcollapse'
        });

        this.quotaPanel = {
            layout: 'form',
            frame: true,
            hideLabels: true,
            width: '100%',
            items: [{
                xtype: 'columnform',
                items: [
                    [this.effetiveUsageField, this.hasOwnQuotaCheckbox, this.quotaField],
                    [this.hasOwnQuotaDescription]
                ]
            }]
        };
        this.items = [{
            layout: 'vbox',
            align: 'stretch',
            pack: 'start',
            border: false,
            items: [
                this.quotaPanel,
                this.byTypeGrid,
                this.byUserGrid
            ]
        }];
        this.supr().initComponent.call(this);
    },

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

        var editDialog = this.findParentBy(function(c){return !!c.record}),
            record = editDialog ? editDialog.record : {};

        Tine.Filemanager.getFolderUsage(record.id, this.onFolderUsageLoad.createDelegate(this));
    },

    onFolderUsageLoad: function(response) {
        var _ = lodash,
            me = this,
            userNameMap = {};

        _.forEach(_.get(response, 'contacts', []), function(contact) {
            userNameMap[contact.id] = contact;
        });

        me.byTypeStore.loadData(_.map(_.get(response, 'type', []), function(o, type) {
            return [type, o.size, o.revision_size];
        }));

        me.byUserStore.loadData(_.map(_.get(response, 'createdBy', []), function(o, user) {
            return [lodash.get(userNameMap, user + '.n_fn' , me.app.i18n._('unknown')), o.size, o.revision_size];
        }));

    },

    onRecordLoad: function(editDialog, record, ticketFn) {
        var _ = window.lodash,
            effectiveQuota = _.get(record, 'data.effectiveAndLocalQuota.effectiveQuota', null),
            effectiveUsage = _.get(record, 'data.effectiveAndLocalQuota.effectiveUsage'),
            quota = +record.get('quota'),
            hasOwnQuota = !!quota;

        this.hasOwnQuotaCheckbox.setDisabled(! lodash.get(record, 'data.account_grants.adminGrant', false)
            || record.get('type') != 'folder');

        this.hasOwnQuotaCheckbox.setValue(hasOwnQuota);
        this.quotaField.setDisabled(! hasOwnQuota);

        this.effetiveUsageField.setValue(Tine.widgets.grid.QuotaRenderer(effectiveUsage, effectiveQuota, true));
    },

    onOwnQuotaCheck: function(cb, checked) {
        this.quotaField.setDisabled(! checked);
        if (! checked) {
            this.quotaField.setValue(null);
        }
    },

    onRecordUpdate: function(editDialog, record) {
        var quota = +this.quotaField.getValue() || null;

        record.set('quota', quota);
    }
});

Ext.reg('Tine.Filemanager.UsagePanel', Tine.Filemanager.UsagePanel);

/***/ }),

/***/ 645:
/***/ (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) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */
Ext.ns('Tine.Filemanager');

Tine.Filemanager.GrantsPanel = Ext.extend(Ext.Panel, {

    /**
     * @cfg {Tine.widgets.dialog.EditDialog}
     */
    editDialog: null,

    /**
     * @cfg {Tine.Tinebase.Application} app
     */
    app: null,

    /**
     * @property {Tine.Filemanager.Model.Node} recordClass
     */
    recordClass: Tine.Filemanager.Model.Node,

    requiredGrant: 'editGrant',
    layout: 'fit',
    border: false,

    initComponent: function() {
        this.app = this.app || Tine.Tinebase.appMgr.get('Filemanager');
        this.title = this.title || this.app.i18n._('Grants');

        this.editDialog.on('load', this.onRecordLoad, this);
        this.editDialog.on('recordUpdate', this.onRecordUpdate, this);

        this.hasOwnGrantsCheckbox = new Ext.form.Checkbox({
            disabled: true,
            boxLabel: this.app.i18n._('This folder has own grants'),
            listeners: {scope: this, check: this.onOwnGrantsCheck}
        });
        this.hasOwnRightsDescription = new Ext.form.Label({
            text: this.app.i18n._("Grants of a folder also apply recursively for all of its sub folders as long they don't have own grants itself.")
        });
        this.pinProtectionCheckbox = new Ext.form.Checkbox({
            disabled: true,
            hidden: ! Tine.Tinebase.areaLocks.hasLock('Tinebase.datasafe'),
            boxLabel: this.app.i18n._('This folder is part of the data safe')
        });
        this.pinProtectionDescription = new Ext.form.Label({
            text: this.app.i18n._("If data safe protection is enabled, this folder and all it's contents is only shown if the data safe is opened.")
        });
        this.grantsGrid = new Tine.widgets.container.GrantsGrid({
            app: this.app,
            alwaysShowAdminGrant: true,
            readOnly: true,
            flex: 1,
            grantContainer: {
                application_id: this.app.id,
                model: 'Filemanager_Model_Node',
            },
        });

        this.items = [{
            layout: 'vbox',
            align: 'stretch',
            pack: 'start',
            border: false,
            items: [{
                layout: 'form',
                frame: true,
                hideLabels: true,
                width: '100%',
                items: [
                    this.hasOwnGrantsCheckbox,
                    this.hasOwnRightsDescription,
                    this.pinProtectionCheckbox,
                    this.pinProtectionDescription
                ]},
                this.grantsGrid
            ]
        }];

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

    onOwnGrantsCheck: function(cb, checked) {
        this.grantsGrid.setReadOnly(!checked);
        this.pinProtectionCheckbox.setDisabled(!checked);
    },

    onRecordLoad: function(editDialog, record, ticketFn) {
        var _ = window.lodash,
            evalGrants = editDialog.evalGrants,
            hasOwnGrants = record.get('acl_node') == record.id,
            hasRequiredGrant = !evalGrants || _.get(record, record.constructor.getMeta('grantsPath') + '.' + this.requiredGrant);

        this.hasOwnGrantsCheckbox.setDisabled(! lodash.get(record, 'data.account_grants.adminGrant', false)
            || record.get('type') != 'folder');
        this.hasOwnGrantsCheckbox.setValue(hasOwnGrants);
        this.pinProtectionCheckbox.setValue(record.get('pin_protected_node') ? true : false);

        this.grantsGrid.useGrant('admin', !!String(record.get('path')).match(/^\/shared/));
        this.grantsGrid.getStore().loadData({results: record.data.grants});

        this.setReadOnly(!hasRequiredGrant);
        this.grantsGrid.setReadOnly(!hasOwnGrants || !hasRequiredGrant);
    },

    setReadOnly: function(readOnly) {
        this.readOnly = readOnly;
        this.grantsGrid.setReadOnly(readOnly);
        this.hasOwnGrantsCheckbox.setDisabled(readOnly);
    },

    onRecordUpdate: function(editDialog, record) {
        var acl_node = this.hasOwnGrantsCheckbox.getValue() ? record.id : null,
            grants = [],
            pin_protected_node = this.pinProtectionCheckbox.getValue() ? true : false;

        this.grantsGrid.getStore().each(function(r) {grants.push(r.data)});

        record.set('acl_node', acl_node);
        record.set('grants', grants);
        record.set('pin_protected_node', pin_protected_node ? acl_node : null);
    }
});

/***/ }),

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

/**
 * 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-2018 Metaways Infosystems GmbH (http://www.metaways.de)
 */

Ext.ns('Tine.Filemanager');

Tine.Filemanager.DocumentPreview = Ext.extend(Ext.FormPanel, {
    /**
     * Node record to preview
     */
    record: null,

    /**
     * filemanager
     */
    app: null,

    /**
     * App which triggered this action
     */
    initialApp: null,

    /**
     * Required for overflow auto
     */
    autoScroll: true,

    /**
     * Overflow auto to enable scrollbar automatically
     */
    overflow: 'auto',

    /**
     * Layout
     */
    layout: 'hfit',

    /**
     * Enable scrollbar
      */
    containsScrollbar: true,

    /**
     * gray fbar
     */
    cls: 'tw-editdialog',

    initComponent: function () {
        this.addEvents(
            /**
             * Fires if no preview is available. Later it should be used to be fired if the browser is not able to load images.
             */
            'noPreviewAvailable'
        );

        this.on('noPreviewAvailable', this.onNoPreviewAvailable, this);

        if (!this.app) {
            this.app = Tine.Tinebase.appMgr.get('Filemanager');
        }

        this.action_close = new Ext.Action({
            text: this.app.i18n._('Close'),
            minWidth: 70,
            scope: this,
            handler: this.onClose,
            iconCls: 'action_cancel'
        });

        this.fbar = ['->', this.action_close];

        Ext.getBody().on('keydown', function (e) {
            switch (e.getKey()) {
                case e.SPACE:
                case e.ESC:
                    this.onClose();
                    break;
                case e.DOWN:
                case e.UP:
                case e.LEFT:
                case e.RIGHT:
                    this.onNavigate(e);
                    break;
                default:
                    break;
            }
        }, this);

        Tine.Filemanager.DocumentPreview.superclass.initComponent.apply(this, arguments);

        if (!this.record) {
            this.fireEvent('noPreviewAvailable');
            return;
        }

        this.loadPreview();
    },

    loadPreview: function () {
        var _ = window.lodash,
            me = this,
            recordClass = this.record.constructor,
            records = [];

        // attachments preview
        if (! recordClass.hasField('preview_count') && recordClass.hasField('attachments')) {
            _.each(this.record.get('attachments'), function(attachmentData) {
                records.push(new Tine.Tinebase.Model.Tree_Node(attachmentData));
            });
        } else if (this.record.get('preview_count')) {
            records.push(this.record);
        } else if (this.hasEmailPreview(this.record)) {
            // @todo fake preview count needed?
            this.record.set('preview_count', 1);

            records.push(this.record);
        }

        records = _.filter(records, function(record) {
            return !!record.get('preview_count');
        });

        if (! records.length) {
            this.fireEvent('noPreviewAvailable');
            return;
        }
        
        this.removeAll(true);
        
        this.afterIsRendered().then(function () {
            _.each(records, function(record) {
                if (me.hasEmailPreview(record)) {
                    me.addEmailDetailsPanel(me, record);
                } else {
                    me.addPreviewPanelForRecord(me, record);
                }
            });
            
            me.doLayout();
        });
    },

    addPreviewPanelForRecord: function (me, record) {
        var _ = window.lodash;
        _.range(record.get('preview_count')).forEach(function (previewNumber) {
            var path = record.get('path'),
                revision = record.get('revision');

            var url = Ext.urlEncode({
                method: 'Tinebase.downloadPreview',
                frontend: 'http',
                _path: path,
                _appId: me.initialApp ? me.initialApp.id : me.app.id,
                _type: 'previews',
                _num: previewNumber,
                _revision: revision
            }, Tine.Tinebase.tineInit.requestUrl + '?');

            me.add({
                html: '<img style="width: 100%;" src="' + url + '" />',
                xtype: 'panel',
                frame: true,
                border: true
            });
        });
    },

    addEmailDetailsPanel: function (me, node) {
        __webpack_require__(647);

        let detailsPanel = new Tine.Felamimail.MailDetailsPanel({
            height: 830, // @todo auto
            autoscroll: true, // @todo scollbar!
            appName: 'Filemanager'
        });
        me.add(detailsPanel);

        Tine.Felamimail.messageBackend.getMessageFromNode(node, {
            success: function(response) {
                // TODO make it work
                var message = Tine.Felamimail.messageBackend.recordReader({responseText: Ext.util.JSON.encode(response.data)});
                this.loadRecord(message.data);
            },
            failure: function (exception) {
                Tine.log.debug(exception);
                // @todo add loadMask?
                // this.getLoadMask().hide();
                // if (exception.code == 404) {
                    this.defaultTpl.overwrite(body, {msg: this.app.i18n._('Message not available.')});
                // } else {
                //     // @todo handle exception?
                // }
            },
            scope: detailsPanel
        });
    },

    hasEmailPreview: function (fileNode) {
        if (! Tine.Tinebase.common.hasRight('run', 'Felamimail')) {
            // needs Felamimail
            return false;
        }

        // define email content-types
        const emailContentTypes = [
            'message/rfc822'
        ];
        if (emailContentTypes.indexOf(fileNode.get('contenttype')) !== -1) {
            return true;
        } else {
            return false;
        }
    },

    /**
     * Fires if no previews are available
     *
     * @todo show more information about preview service + configuration
     */
    onNoPreviewAvailable: function () {
        var me = this;
        me.afterIsRendered().then(function() {
            me.removeAll(true);
            me.add({
                html: '<b>' + me.app.i18n._('No preview available.') + '</b>',
                xtype: 'panel',
                frame: true,
                border: true
            });
            me.doLayout();
        });
    },

    onNavigate: function(e) {
        if (this.sm) {
            switch (e.getKey()) {
                case e.DOWN:
                    this.sm.selectNext();
                    break;
                case e.UP:
                    this.sm.selectPrevious();
                    break;
                default:
                    break;
            }

            if (this.sm.getSelected() !== this.record) {
                this.record = this.sm.getSelected();
                this.removeAll(true);
                this.loadPreview();
            }

        }
    },
    /**
     * @private
     */
    onClose : function(){
        this.fireEvent('cancel');
        this.purgeListeners();
        this.window.close();
    }
});

Tine.Filemanager.DocumentPreview.openWindow = function (config) {
    var id = (config.record && config.record.id) ? config.record.id : 0;
    return Tine.WindowFactory.getWindow({
        width: (screen.height * 0.8) / Math.sqrt(2), // DIN A4 and so on
        height: screen.height * 0.8,
        name: Tine.Filemanager.DocumentPreview.prototype.windowNamePrefix + id,
        contentPanelConstructor: 'Tine.Filemanager.DocumentPreview',
        contentPanelConstructorConfig: config,
        modal: false,
        windowType: 'Browser'
    });
};


/***/ }),

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

/*
 * Tine 2.0
 *
 * @package     Felamimail
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Michael Spahn <m.spahn@metaways.de>
 * @copyright   Copyright (c) 2017-2018 Metaways Infosystems GmbH (http://www.metaways.de)
 */

Ext.ns('Tine.Felamimail');

/**
 * @namespace   Tine.Felamimail
 * @class       Tine.Felamimail.MailDetailsPanel
 * @extends     Ext.Panel
 *
 * @todo: use in/instead of Tine.Felamimail.GridDetailsPanel (this one is more configurable()
 */
Tine.Felamimail.MailDetailsPanel = Ext.extend(Ext.Panel, {
    record: null,
    app: null,
    appName: null,
    nodeRecord: null,

    initComponent: function () {
        this.app = Tine.Tinebase.appMgr.get(this.appName);
        Tine.Felamimail.MailDetailsPanel.superclass.initComponent.call(this);
    },

    /**
     * add on click event after render
     * @private
     */
    afterRender: function () {
        Tine.Felamimail.MailDetailsPanel.superclass.afterRender.apply(this, arguments);
        this.body.on('click', this.onClick, this);
    },

    /**
     * init single message template (this.tpl)
     */
    initTemplate: function () {
        var me = this;

        this.tpl = new Ext.XTemplate(
            '<div class="preview-panel-mail">',
            '<div class="preview-panel-mail-headers">',
            '<b>' + this.app.i18n._('Subject') + ':</b> {[this.encode(values.subject)]}<br/>',
            '<b>' + this.app.i18n._('From') + ':</b>',
            ' {[this.showFrom(values.from_email, values.from_name, "' + this.app.i18n._('Add') + '", "'
            + this.app.i18n._('Add contact to addressbook') + '")]}<br/>',
            '<b>' + this.app.i18n._('Date') + ':</b> {[this.showDate(values.sent, values)]}',
            '{[this.showRecipients(values.headers)]}',
            '{[this.showHeaders("' + this.app.i18n._('Show or hide header information') + '")]}',
            '</div>',
            '<div class="preview-panel-mail-attachments">{[this.showAttachments(values.attachments, values)]}</div>',
            '<div class="preview-panel-mail-body">{values.body}</div>',
            '</div>', {
                app: me.app,
                panel: me,
                encode: function (value) {
                    if (value) {
                        var encoded = Ext.util.Format.htmlEncode(value);
                        encoded = Ext.util.Format.nl2br(encoded);
                        // it should be enough to replace only 2 or more spaces
                        encoded = encoded.replace(/ /g, '&nbsp;');

                        return encoded;
                    } else {
                        return '';
                    }
                },

                showDate: function (sent, recordData) {
                    var date = sent
                        ? (Ext.isDate(sent) ? sent : Date.parseDate(sent, Date.patterns.ISO8601Long))
                        : Date.parseDate(recordData.received, Date.patterns.ISO8601Long);
                    return date ? date.format('l') + ', ' + Tine.Tinebase.common.dateTimeRenderer(date) : '';
                },

                showFrom: function (email, name, addText, qtip) {
                    if (name === null || name === undefined) {
                        return '';
                    }

                    var result = this.encode(name + ' <' + email + '>');

                    // add link with 'add to contacts'
                    var id = Ext.id() + ':' + email;

                    var nameSplit = name.match(/^"*([^,^ ]+)(,*) *(.+)/i);
                    var firstname = (nameSplit && nameSplit[1]) ? nameSplit[1] : '';
                    var lastname = (nameSplit && nameSplit[3]) ? nameSplit[3] : '';
                    if (nameSplit && nameSplit[2] == ',') {
                        firstname = lastname;
                        lastname = nameSplit[1];
                    }

                    id += Ext.util.Format.htmlEncode(':' + Ext.util.Format.trim(firstname) + ':' + Ext.util.Format.trim(lastname));
                    result = '<a id="' + id + '" class="tinebase-email-link">' + result + '</a>'
                    result += ' <span ext:qtip="' + Tine.Tinebase.common.doubleEncode(qtip) + '" id="' + id + '" class="tinebase-addtocontacts-link">[+]</span>';
                    return result;
                },

                showHeaders: function (qtip) {
                    var result = ' <span ext:qtip="' + Tine.Tinebase.common.doubleEncode(qtip) + '" id="' + Ext.id() + ':show" class="tinebase-showheaders-link">[...]</span>';
                    return result;
                },

                showRecipients: function (value) {
                    if (value) {
                        var result = '';
                        for (header in value) {
                            if (value.hasOwnProperty(header) && (header == 'to' || header == 'cc' || header == 'bcc')) {
                                result += '<br/><b>' + this.app.i18n._hidden(Ext.util.Format.capitalize(header)) + ':</b> '
                                    + Ext.util.Format.htmlEncode(value[header]);
                            }
                        }
                        return result;
                    } else {
                        return '';
                    }
                },

                showAttachments: function (attachments) {
                    var result = '';

                    if (attachments && attachments.length > 0) {
                        result = '<b>' + this.app.i18n._('Attachments') + ':</b> ';

                        for (var i = 0, id; i < attachments.length; i++) {
                            result += '<span id="' + Ext.id() + ':' + i + '" class="tinebase-download-link">'
                                + '<i>' + attachments[i].filename + '</i>'
                                + ' (' + Ext.util.Format.fileSize(attachments[i].size) + ')</span> ';
                        }
                    }

                    return result;
                }
            });
        this.tpl.apply(this.record);
    },

    /**
     * on click for attachment download / compose dlg / edit contact dlg
     *
     * @private
     */
    onClick: function (e) {
        var selectors = [
            'span[class=tinebase-download-link]',
            'a[class=tinebase-email-link]',
            'span[class=tinebase-addtocontacts-link]',
            'span[class=tinebase-showheaders-link]'
        ];

        // find the correct target
        for (var i = 0, target = null, selector = ''; i < selectors.length; i++) {
            target = e.getTarget(selectors[i]);
            if (target) {
                selector = selectors[i];
                break;
            }
        }

        switch (selector) {
            case 'span[class=tinebase-download-link]':
                var idx = target.id.split(':')[1],
                    attachment = this.record.attachments[idx];

                // remove part id if set (that is the case in message/rfc822 attachments)
                var messageId = (this.record.id.match(/_/)) ? this.record.id.split('_')[0] : this.record.id;

                if (attachment['content-type'] === 'message/rfc822') {
                    // display message
                    var window = Tine.Felamimail.MessageDisplayDialog.openWindow({
                        message: new Tine.Felamimail.Model.Message({
                            id: messageId + '_' + attachment.partId
                        })
                    });

                } else {

                    // TODO allow download for attachments of imap messages

                    new Ext.ux.file.Download({
                        params: {
                            requestType: 'HTTP',
                            method: 'Felamimail.downloadNodeAttachment',
                            // method: this.appName + '.downloadAttachment',
                            // path: this.nodeRecord.data.path,
                            nodeId: this.record.id,
                            partId: attachment.partId
                        }
                    }).start();
                }

                break;

            case 'a[class=tinebase-email-link]':
                // open compose dlg
                var email = target.id.split(':')[1];
                var defaults = Tine.Felamimail.Model.Message.getDefaultData();
                defaults.to = [email];
                defaults.body = Tine.Felamimail.getSignature();

                var message = new Tine.Felamimail.Model.Message(defaults, 0);
                Tine.Felamimail.MessageEditDialog.openWindow({
                    message: message
                });
                break;

            case 'span[class=tinebase-addtocontacts-link]':
                // open edit contact dlg

                // check if addressbook app is available
                if (!Tine.Addressbook || !Tine.Tinebase.common.hasRight('run', 'Addressbook')) {
                    return;
                }

                var id = Ext.util.Format.htmlDecode(target.id);
                var parts = id.split(':');

                Tine.Addressbook.ContactEditDialog.openWindow({
                    listeners: {
                        scope: this,
                        'load': function (editdlg) {
                            editdlg.record.set('email', parts[1]);
                            editdlg.record.set('n_given', parts[2]);
                            editdlg.record.set('n_family', parts[3]);
                        }
                    }
                });

                break;

            case 'span[class=tinebase-showheaders-link]':
                // show headers

                var parts = target.id.split(':');
                var targetId = parts[0];
                var action = parts[1];

                var html = '';
                if (action == 'show') {
                    var messageHeaders = this.record.headers;

                    for (header in messageHeaders) {
                        if (messageHeaders.hasOwnProperty(header) && (header != 'to' || header != 'cc' || header != 'bcc')) {
                            html += '<br/><b>' + header + ':</b> '
                                + Ext.util.Format.htmlEncode(messageHeaders[header]);
                        }
                    }

                    target.id = targetId + ':' + 'hide';

                } else {
                    html = ' <span ext:qtip="' + Ext.util.Format.htmlEncode(this.app.i18n._('Show or hide header information')) + '" id="'
                        + Ext.id() + ':show" class="tinebase-showheaders-link">[...]</span>'
                }

                target.innerHTML = html;

                break;
        }
    },

    /**
     * fills this fields with the corresponding message data
     *
     * @param {Tine.Tinebase.data.Record|Object} record
     */
    loadRecord: function (record) {
        if (record.data) {
            // TODO improve model detection
            this.record = record.data.hasOwnProperty('message') ? record.data.message : record;
            this.nodeRecord = record;
        } else {
            // TODO use model? here we only get the "data" part of the message record
            this.record = record;
        }
        this.initTemplate();
        this.update(this.record);
    }
});


/***/ }),

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

/*
 * Tine 2.0
 *
 * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
 * @author      Michael Spahn <m.spahn@metaways.de>
 * @copyright   Copyright (c) 2017 Metaways Infosystems GmbH (http://www.metaways.de)
 */

Ext.ns('Tine.Filemanager');

Tine.Filemanager.FilePublishedDialog = Ext.extend(Ext.Panel, {
    /**
     * Tine.Filemanager.Model.DownloadLink
     */
    record: null,

    /**
     * Password used to protect downloadlink
     */
    password: null,

    /**
     * Filemanager
     */
    app: null,

    windowNamePrefix: 'FilePublishedDialog_',

    layout: 'fit',
    border: false,
    frame: false,

    /**
     * Constructor.
     */
    initComponent: function () {
        if (!this.app) {
            this.app = Tine.Tinebase.appMgr.get('Filemanager');
        }

        this.items = [{
            border: false,
            frame: true,
            layout: 'border',
            items: [{
                region: 'center',
                xtype: 'columnform',
                labelAlign: 'top',
                formDefaults: {
                    xtype: 'textfield',
                    anchor: '100%',
                    labelSeparator: '',
                    columnWidth: .333
                },
                items: [
                    [{
                        columnWidth: 1,
                        fieldLabel: this.app.i18n._('Url'),
                        name: 'url',
                        value: this.record.get('url'),
                        maxLength: 100,
                        allowBlank: true,
                        readOnly: true
                    }, {
                        columnWidth: 1,
                        fieldLabel: this.app.i18n._('Password'),
                        name: 'url',
                        value: this.password,
                        xtype: 'tw-passwordTriggerField',
                        allowBlank: true,
                        editable: false
                    }, {
                        columnWidth: 1,
                        fieldLabel: this.app.i18n._('Valid until'),
                        name: 'url',
                        xtype: 'datefield',
                        editable: false,
                        readOnly: true,
                        value: this.record.get('expiry_time')
                    }]
                ]
            }]
        }];

        var me = this;

        this.tbar = [];

        if (Tine.Tinebase.appMgr.isEnabled('Felamimail')) {
            this.sendByMailAction = new Ext.Action({
                disabled: false,
                text: this.app.i18n._('Send as e-mail'),
                iconCls: 'action_composeEmail',
                minWidth: 70,
                handler: this.onSendAsMail.createDelegate(me),
                scope: this
            });
            this.tbar.push(this.sendByMailAction);
        }


        Tine.Filemanager.FilePublishedDialog.superclass.initComponent.call(this);
    },

    onSendAsMail: function () {
        var body =  this.app.i18n._("Download") + ": " + this.record.get('url');

        if (this.password) {
            body += "\n" + this.app.i18n._("Password") + ": " + this.password;
        }

        var record = new Tine.Felamimail.Model.Message({
            'body': body
        });

        Tine.Felamimail.MessageEditDialog.openWindow({
            record: record
        });
    }
});

Tine.Filemanager.FilePublishedDialog.openWindow = function (config) {
    var id = (config.record && config.record.id) ? config.record.id : 0;
    return Tine.WindowFactory.getWindow({
        width: 350,
        height: 200,
        name: Tine.Filemanager.FilePublishedDialog.prototype.windowNamePrefix + id,
        contentPanelConstructor: 'Tine.Filemanager.FilePublishedDialog',
        contentPanelConstructorConfig: config,
        modal: true
    });
};


/***/ }),

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

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

Tine.Filemanager.NotificationPanel = Ext.extend(Ext.Panel, {
    editDialog: null,
    app: null,

    layout: 'fit',
    border: false,

    requiredGrant: 'readGrant',

    notificationGrid: null,

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

        this.app = this.app || Tine.Tinebase.appMgr.get('Filemanager');
        this.title = this.title || this.app.i18n._('Notifications');

        this.editDialog.on('load', this.onRecordLoad, this);
        this.editDialog.on('save', this.onSave, this);

        var store = new Ext.data.JsonStore({
            fields: ['active', 'summary', 'accountId', 'accountType', 'accountName'],
            idProperty: 'accountId'
        });

        this.notificationGrid = new Tine.Filemanager.NotificationGridPanel({
            store: store,
            readOnly: true,
            flex: 1,
            editDialog: this.editDialog
        });

        this.hasOwnNotificationSettings = new Ext.form.Checkbox({
            checked: false,
            disabled: true,
            boxLabel: this.app.i18n._('This folder has own notification settings'),
            listeners: {scope: this, check: this.onOwnNotificationCheck}
        });

        this.items = [{
            layout: 'vbox',
            align: 'stretch',
            pack: 'start',
            border: false,
            items: [{
                layout: 'form',
                frame: true,
                hideLabels: true,
                width: '100%',
                items: [
                    this.hasOwnNotificationSettings
                ]
            },
                this.notificationGrid
            ]
        }];

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

    onOwnNotificationCheck: function (cb, checked) {
        this.notificationGrid.setReadOnly(!checked);

        if (!checked) {
            this.notificationGrid.getStore().removeAll();
        }
    },

    onRecordLoad: function (editDialog, record, ticketFn) {
        var _ = window.lodash,
            featureEnabled = _.get(Tine.Tinebase.configManager.get('filesystem'), 'enableNotifications', false),
            notificationProps = window.lodash.get(record, 'data.notificationProps', []),
            hasOwnNotificationSettings = !!notificationProps.length,
            evalGrants = editDialog.evalGrants,
            hasRequiredGrant = !evalGrants || _.get(record, record.constructor.getMeta('grantsPath') + '.' + this.requiredGrant),
            hasAdminGrant = _.get(this.editDialog, 'record.data.account_grants.adminGrant', false);

        this.notificationGrid.getStore().loadData(_.get(record, 'data.notificationProps', []), false);
        this.hasOwnNotificationSettings.setValue(hasOwnNotificationSettings);

        // @TODO: enable box for non admins if not hasOwnNotificationSettings
        //        atm. the server can't cope with it -> see #490, #484
        // this.hasOwnNotificationSettings.setDisabled(!featureEnabled || !hasRequiredGrant || (hasOwnNotificationSettings && !hasAdminGrant))
        this.hasOwnNotificationSettings.setDisabled(!hasAdminGrant);

        this.notificationGrid.setReadOnly(!featureEnabled || !hasRequiredGrant || !hasOwnNotificationSettings);
    },

    onSave: function (editDialog, record, ticketFn) {
        var _ = window.lodash;

        // Remove properties
        _.get(record, 'data.notificationProps', []);

        var data = [];

        this.notificationGrid.getStore().each(function (record) {
            // prevent to send accountName here
            data.push({
                'active': record.data.active,
                'summary': record.data.summary,
                'accountId': record.data.accountId,
                'accountType': record.data.accountType
            });
        });

        record.set('notificationProps', data);
    }
});

/***/ }),

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

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

Tine.Filemanager.NotificationGridPanel = Ext.extend(Tine.widgets.account.PickerGridPanel, {
    app: null,

    selectType: 'both',
    selectAnyone: false,
    selectMyself: true,

    userCombo: null,
    groupCombo: null,

    currentUser: null,

    editDialog: null,
    actionUpdater: null,

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

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

        // init actions
        this.actionUpdater = new Tine.widgets.ActionUpdater({
            recordClass: Tine.Filemanager.Model.Node,
            evalGrants: true
        });

        this.currentUser = Tine.Tinebase.registry.get('currentAccount');
        this.initColumns();

        if (!_.get(this.editDialog, 'record.data.account_grants.adminGrant', false)) {
            this.selectType = 'myself';
        }

        Tine.Filemanager.NotificationGridPanel.superclass.initComponent.apply(this, arguments);


        this.on('beforeedit', this.onBeforeEdit.createDelegate(this));

        this.getSelectionModel().on('selectionchange', function (sm) {
            this.actionUpdater.updateActions(sm);
        }, this);
    },

    initColumns: function () {
        var me = this;
        this.configColumns = [
            new Ext.ux.grid.CheckColumn({
                id: 'active',
                header: this.app.i18n._('Notification'),
                tooltip: this.app.i18n._('Notification active'),
                dataIndex: 'active',
                width: 55,
                onBeforeCheck: function (checkbox, record) {
                    return this.checkGrant(record);
                }.createDelegate(me)
            }), {
                id: 'summary',
                dataIndex: 'summary',
                width: 150,
                sortable: true,
                header: this.app.i18n._('Summary'),
                renderer: function (value) {
                    return value ?
                        String.format(me.app.i18n.ngettext('Once a Day', 'Every {0} Days', value), value) :
                        me.app.i18n._('No');
                },
                editor: new Ext.form.ComboBox({
                    triggerAction: 'all',
                    lazyRender: false,
                    editable: false,
                    mode: 'local',
                    forceSelection: true,
                    allowBlank: false,
                    expandOnFocus: true,
                    blurOnSelect: true,
                    autoSelect: true,
                    store: [
                        [0, me.app.i18n._('Don\'t summarize')],
                        [1, me.app.i18n._('Once a day')],
                        [3, me.app.i18n._('Every 3 days')],
                        [7, me.app.i18n._('Once a week')],
                        [30, me.app.i18n._('Once a month')], // somehow once a month
                        [365, me.app.i18n._('Once a year')] // somehow once a year
                    ]
                })
            }
        ];
    },

    onBeforeEdit: function (e) {
        return this.checkGrant(e.record);
    },

    checkGrant: function (record) {
        var _ = window.lodash;

        var userHasAdminGrant = _.get(this.editDialog, 'record.data.account_grants.adminGrant', false);

        // get id if it's from notification props, if its a record which was added or if it's a group which was added
        var id = (_.get(record, 'data.account_id', _.get(record, 'data.accountId')) || _.get(record, 'data.group_id')) || record.id;

        if (!userHasAdminGrant && id !== this.currentUser.accountId) {
            return false;
        }

        return true;
    },

    getColumnModel: function () {
        if (!this.colModel) {
            this.colModel = new Ext.grid.ColumnModel({
                defaults: {
                    sortable: true
                },
                columns: [
                    {
                        id: 'name',
                        header: this.app.i18n._('Name'),
                        dataIndex: this.recordPrefix + 'name',
                        renderer: this.accountRenderer.createDelegate(this)
                    }
                ].concat(this.configColumns)
            });
        }

        return this.colModel;
    },

    accountRenderer: function (value, meta, record) {
        if (!record) {
            return '';
        }

        var _ = window.lodash;

        var iconCls = 'tine-grid-row-action-icon ' + (_.get(record, 'data.accountType') === 'user' ? 'renderer renderer_accountUserIcon' : 'renderer_accountGroupIcon');

        return '<div class="' + iconCls + '">&#160;</div>' + Ext.util.Format.htmlEncode(_.get(record, 'data.accountName') || value);
    },

    resetCombobox: function (combo) {
        combo.collapse();
        combo.clearValue();
        combo.reset();
    },

    getContactSearchCombo: function () {
        if (!this.userCombo) {
            this.userCombo = new Tine.Addressbook.SearchCombo({
                hidden: true,
                accountsStore: this.store,
                emptyText: i18n._('Search for users ...'),
                newRecordClass: this.recordClass,
                newRecordDefaults: this.recordDefaults,
                recordPrefix: this.recordPrefix,
                userOnly: true,
                additionalFilters: (this.showHidden) ? [{field: 'showDisabled', operator: 'equals', value: true}] : []
            });

            this.userCombo.onSelect = this.onAddRecordFromCombo.createDelegate(this, [this.userCombo], true);
        }

        return this.userCombo;
    },

    onAddMyself: function () {
        var currentUser = Tine.Tinebase.registry.get('currentAccount'),
            record,
            recordData = (this.recordDefaults !== null) ? this.recordDefaults : {};

        // user record
        recordData['active'] = true;
        recordData['summary'] = null;
        recordData['accountId'] = currentUser.accountId;
        recordData['accountType'] = 'user';
        recordData['accountName'] = currentUser.accountDisplayName;

        record = new this.recordClass(recordData, currentUser.accountId);

        // check if already in
        if (! this.store.getById(record.id)) {
            this.store.add([record]);
        }
    },

    onAddRecordFromCombo: function (recordToAdd, index, combo) {
        var _ = window.lodash,
            id = _.get(recordToAdd, 'data.account_id') || _.get(recordToAdd, 'data.group_id');

        // If there is no admin grant, only allow to edit the own record
        if (!_.get(this.editDialog, 'record.data.account_grants.adminGrant', false) && id !== this.currentUser.accountId) {
            Ext.Msg.alert(i18n._('No permission'), 'You are only allowed to edit your own notifications.');

            this.resetCombobox(combo);
            return false;
        }

        var record = {
            'active': true,
            'summary': null,
            'accountId': id,
            'accountType': _.get(recordToAdd, 'data.type', null),
            'accountName': _.get(recordToAdd, 'data.n_fileas') || _.get(recordToAdd, 'data.name') || i18n._('all')
        };

        if (this.store.getById(id)) {
            this.resetCombobox(combo);
            return false;
        }

        this.store.loadData([record], true);

        this.resetCombobox(combo);

    },

    /**
     * init actions and toolbars
     */
    initActionsAndToolbars: function () {
        this.actionRemove = new Ext.Action({
            text: i18n._('Remove record'),
            disabled: true,
            scope: this,
            handler: this.onRemove,
            iconCls: 'action_deleteContact',
            actionUpdater: function (action, grants, records, isFilterSelect) {
                var adminGrant = window.lodash.get(this.editDialog, 'record.data.account_grants.adminGrant', false),
                    accountId = window.lodash.get(records, '[0].data.accountId', null);

                if (accountId !== null) {
                    action.setDisabled(!adminGrant && (accountId !== this.currentUser.accountId));
                }
            }
        });

        var contextItems = [this.actionRemove];
        this.contextMenu = new Ext.menu.Menu({
            plugins: [{
                ptype: 'ux.itemregistry',
                key: 'Tinebase-MainContextMenu'
            }],
            items: contextItems.concat(this.contextMenuItems)
        });

        // removes temporarily added items
        this.contextMenu.on('hide', function () {
            if (this.contextMenu.hasOwnProperty('tempItems') && this.contextMenu.tempItems.length) {
                Ext.each(this.contextMenu.tempItems, function (item) {
                    this.contextMenu.remove(item.itemId);
                }, this);
            }
            this.contextMenu.tempItems = [];
        }, this);

        if (this.enableBbar) {
            this.bbar = new Ext.Toolbar({
                items: [
                    this.actionRemove
                ].concat(this.contextMenuItems)
            });
        }

        if (this.enableTbar) {
            this.initTbar();
        }

        this.actionUpdater.addActions([this.actionRemove]);
    },

    onRemove: function () {
        var selectedRows = this.getSelectionModel().getSelections();
        for (var i = 0; i < selectedRows.length; ++i) {
            if (this.checkGrant(selectedRows[i])) {
                this.store.remove(selectedRows[i]);
            }
        }
    },

    getGroupSearchCombo: function () {
        if (!this.groupCombo) {
            this.groupCombo = new Tine.Tinebase.widgets.form.RecordPickerComboBox({
                hidden: true,
                accountsStore: this.store,
                blurOnSelect: true,
                recordClass: this.groupRecordClass,
                newRecordClass: this.recordClass,
                newRecordDefaults: this.recordDefaults,
                recordPrefix: this.recordPrefix,
                emptyText: this.app.i18n._('Search for groups ...')
            });

            this.groupCombo.onSelect = this.onAddRecordFromCombo.createDelegate(this, [this.groupCombo], true);
        }

        return this.groupCombo;
    }
})
;

/***/ }),

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

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

Tine.Filemanager.RevisionPanel = Ext.extend(Ext.form.FieldSet, {

    editDialog: null,
    app: null,

    layout: 'hfit',

    keep: null,

    keepNum: null,
    keepNumInput: null,

    keepMonth: null,
    keepMonthInput: null,

    config: null,
    readOnly: false,

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

        this.config = Tine.Tinebase.configManager.get('filesystem');

        this.app = this.app || Tine.Tinebase.appMgr.get('Filemanager');
        this.title = this.title || this.app.i18n._('Revision');

        this.editDialog.on('load', this.onRecordLoad, this);
        this.editDialog.on('save', this.onSave, this);

        var type = _.get(this.editDialog, 'record.data.type');
        var adminGrant = _.get(this.editDialog, 'record.data.account_grants.adminGrant', false);

        if (type !== 'folder' || !adminGrant) {
            this.readOnly = true;
        }

        this.hasOwnRevisionSettings = new Ext.form.Checkbox({
            checked: false,
            disabled: this.readOnly,
            boxLabel: this.app.i18n._('This folder has own revision settings'),
            listeners: {scope: this, check: this.onOwnRevisionCheck}
        });

        this.items = [{
            items: [this.hasOwnRevisionSettings, [{
                xtype: 'container',
                cls: 'revision-container',
                margins: '0 20 0 0',
                items: [{
                    xtype: 'checkbox',
                    boxLabel: this.app.i18n._('Revision active'),
                    name: 'keep',
                    columnWidth: 1,
                    readOnly: false,
                    disabled: false,
                    ref: '../../keep',
                    listeners: {scope: this, check: this.onKeepCheck}
                }, {
                    xtype: 'container',
                    cls: 'revision-checkbox-field',
                    items: [{
                        xtype: 'checkbox',
                        boxLabel: this.app.i18n._('Limit revision amount to'),
                        name: 'keepNum',
                        columnWidth: 1,
                        readOnly: false,
                        disabled: false,
                        ref: '../../../keepNum',
                        listeners: {scope: this, check: this.onKeepNumCheck}
                    }, {
                        xtype: 'numberfield',
                        ref: '../../../keepNumInput'
                    }]
                }, {
                    xtype: 'container',
                    cls: 'revision-checkbox-field',
                    items: [{
                        xtype: 'checkbox',
                        boxLabel: this.app.i18n._('Hold-back in months'),
                        name: 'keepMonth',
                        columnWidth: 1,
                        readOnly: false,
                        disabled: false,
                        ref: '../../../keepMonth',
                        listeners: {scope: this, check: this.onKeepMonthCheck}
                    }, {
                        xtype: 'numberfield',
                        ref: '../../../keepMonthInput'
                    }]
                }]
            }]]
        }];

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

        this.manageFields();
    },

    onKeepCheck: function (cb, checked) {
        this.manageFields();

        if (false === checked) {
            this.keepNum.setValue(false);
            this.keepMonth.setValue(false);
        }
    },

    onKeepNumCheck: function (cb, checked) {
        this.manageFields();

        if (false === checked) {
            this.keepNumInput.setValue(null);
        }
    },

    onKeepMonthCheck: function (cb, checked) {
        this.manageFields();

        if (false === checked) {
            this.keepMonthInput.setValue(null);
        }
    },

    manageFields: function () {
        this.keep.setDisabled(this.readOnly || false === this.hasOwnRevisionSettings.getValue());

        this.keepNum.setDisabled(this.keep.disabled || false === this.keep.getValue());
        this.keepNumInput.setDisabled(this.keep.disabled || false === this.keep.getValue() || false === this.keepNum.getValue());

        this.keepMonth.setDisabled(this.keep.disabled || false === this.keep.getValue());
        this.keepMonthInput.setDisabled(this.keep.disabled || false === this.keep.getValue() || false === this.keepMonth.getValue());
    },

    onOwnRevisionCheck: function (cb, checked) {
        this.manageFields();
    },

    onRecordLoad: function (editDialog, record, ticketFn) {
        var _ = window.lodash;

        this.hasOwnRevisionSettings.setValue(record.id === _.get(record, 'data.revisionProps.nodeId'));
        this.keep.setValue(_.get(record, 'data.revisionProps.keep', _.get(this.config, 'modLogActive', false)));

        if (_.get(record, 'data.revisionProps.keepNum', _.get(this.config, 'numKeepRevisions', false))) {
            this.keepNum.setValue(true);
            this.keepNumInput.setValue(_.get(record, 'data.revisionProps.keepNum', _.get(this.config, 'numKeepRevisions')));
        }

        if (_.get(record, 'data.revisionProps.keepMonth', _.get(this.config, 'monthKeepRevisions', false))) {
            this.keepMonth.setValue(true);
            this.keepMonthInput.setValue(_.get(record, 'data.revisionProps.keepMonth', _.get(this.config, 'monthKeepRevisions')));
        }
    },

    onSave: function (editDialog, record, ticketFn) {
        if (this.readOnly) {
            return;
        }

        var _ = window.lodash;

        // In case there is no own setting, we don't need to persist current values we just empty it
        // When reloaded the server is supposed to send the correct inherited values
        if (false === this.hasOwnRevisionSettings.getValue()) {
            _.set(record, 'data.revisionProps', {});
            return;
        }

        var data = {};

        _.set(data, 'nodeId', record.id);
        _.set(data, 'keep', this.keep.getValue());
        _.set(data, 'keepNum', this.keepNumInput.getValue());
        _.set(data, 'keepMonth', this.keepMonthInput.getValue());

        _.set(record, 'data.revisionProps', data);
    }
});

/***/ }),

/***/ 652:
/***/ (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__(653);
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!./Filemanager.css", function() {
			var newContent = require("!!../../Tinebase/js/node_modules/css-loader/index.js!./Filemanager.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(); });
}

/***/ }),

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

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


// module
exports.push([module.i, "/**\n * Tine 2.0\n * \n * @package     Filemanager\n * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3\n * @author      Martin Jatho <m.jatho@metaways.de>\n * @copyright   Copyright (c) 2007-2011 Metaways Infosystems GmbH (http://www.metaways.de)\n * @version     $Id: Tasks.css 3797 2008-08-11 08:33:21Z c.weiss@metaways.de $\n *\n */\n\n.FilemanagerIconCls, .tine-recordclass-gridicon.FilemanagerNode {\n    background-image:url(" + __webpack_require__(654) + ");\n}\n\n.action_filemanager_folder_up {\n    background-image:url(" + __webpack_require__(655) + ") !important;\n}\n\n.action_filemanager_save_all {\n    background-image:url(" + __webpack_require__(20) + ") !important;\n}\n\n/* @TODO improve me */\n.action_filemanager_data_safe_locked {\n    background-image:url(" + __webpack_require__(105) + ") !important;\n}\n\n/* @TODO improve me */\n.action_filemanager_data_safe_unlocked {\n    background-image:url(" + __webpack_require__(106) + ") !important;\n}\n\n.action_pause {\n    background-image:url(" + __webpack_require__(656) + ") !important;\n    background-repeat: no-repeat;\n}\n\n.action_resume {\n    background-image:url(" + __webpack_require__(657) + ") !important;\n    background-repeat: no-repeat;\n}\n\n.action_create_folder {\n    background-image:url(" + __webpack_require__(89) + ") !important;\n}\n\n.x-type-data-safe .x-tree-node-icon,\n.x-type-data-safe .x-tinebase-typefolder .x-grid3-cell-inner {\n    background-image:url(" + __webpack_require__(658) + ") !important;\n\n}\n\n.x-type-data-safe.x-tree-node-expanded .x-tree-node-icon {\n    background-image:url(" + __webpack_require__(659) + ") !important;\n}\n\n.x-tree-node .x-type-data-safe a span,\n.x-type-data-safe td {\n    color: red;\n}\n\n.x-btn.x-type-data-safe button {\n    filter: hue-rotate(-140deg)\n}\n\ntable.x-btn.x-type-data-safe {\n    filter: hue-rotate(140deg)\n}\n\n\n.x-tinebase-typefolder .x-grid3-cell-inner {\n    background-image:url(" + __webpack_require__(18) + ");\n    background-repeat: no-repeat;\n    background-size: 16px;\n    padding-left: 19px;\n}\n\n.x-tinebase-virus .x-grid3-cell-inner {\n    background-image:url(" + __webpack_require__(660) + ");\n    background-repeat: no-repeat;\n    background-size: 16px;\n    padding-left: 19px;\n}\n\n.action_publish {\n    background-image: url(" + __webpack_require__(661) + ") !important;\n    background-repeat: no-repeat;\n}\n\n.revision-checkbox-field .x-form-check-wrap {\n    display: inline;\n}\n\n.revision-checkbox-field input:last-child {\n    margin-left: 5px;\n}\n\n.revision-container {\n    margin-left: 20px;\n}", ""]);

// exports


/***/ }),

/***/ 654:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath d='M37.4,19.1H5.7c-0.2,0-0.4,0.1-0.5,0.2C5,19.4,5,19.6,5,19.8l2.7,14.4c0.1,0.3,0.3,0.5,0.7,0.5h26.3c0.4,0,0.6-0.2,0.7-0.5 l2.7-14.4c0-0.2,0-0.3-0.2-0.5C37.8,19.2,37.7,19.1,37.4,19.1z M33,31.8c-0.1,0.3-0.3,0.5-0.7,0.5l-21.5,0c-0.3,0-0.6-0.2-0.7-0.5 l-1.8-9.2c0-0.2,0-0.3,0.2-0.5C8.6,22,8.8,21.9,9,21.9h25.2c0.2,0,0.4,0.1,0.5,0.2c0.1,0.1,0.2,0.3,0.2,0.5L33,31.8z M9.8,18.1H7.2 V8.1c0-0.5,0.4-0.8,1-0.8h7.6c0.3,0,0.7,0.2,0.8,0.4l1.4,2h17c0.5,0,1,0.4,1,0.8v7.7h-2.8v-5.8H9.8V18.1z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 655:
/***/ (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' width='42.5' height='42.5'%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 M20.8,18c0.3,0,0.5,0.1,0.7,0.3l5.2,5.2c0.2,0.2,0.3,0.4,0.3,0.7 c0,0.3-0.1,0.5-0.3,0.7l-0.6,0.6c-0.2,0.2-0.4,0.3-0.7,0.3s-0.5-0.1-0.7-0.3l-2.3-2.3v11.2c0,0.3-0.1,0.5-0.3,0.7 c-0.2,0.2-0.4,0.3-0.7,0.3h-1c-0.3,0-0.5-0.1-0.7-0.3c-0.2-0.2-0.3-0.4-0.3-0.7V23.2l-2.3,2.3c-0.2,0.2-0.4,0.3-0.7,0.3 s-0.5-0.1-0.7-0.3l-0.6-0.6c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7l5.2-5.2C20.2,18.1,20.5,18,20.8,18z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 656:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath d='M35.6,21c0-2.6-0.7-5.1-2-7.3s-3.1-4-5.3-5.3s-4.7-2-7.3-2s-5.1,0.7-7.3,2s-4,3.1-5.3,5.3s-2,4.7-2,7.3s0.7,5.1,2,7.3 s3.1,4,5.3,5.3s4.7,2,7.3,2s5.1-0.7,7.3-2s4-3.1,5.3-5.3S35.6,23.6,35.6,21z M38,21c0,3.1-0.8,5.9-2.3,8.5c-1.5,2.6-3.6,4.7-6.2,6.2 C26.9,37.2,24.1,38,21,38c-3.1,0-5.9-0.8-8.5-2.3c-2.6-1.5-4.7-3.6-6.2-6.2S4,24.1,4,21c0-3.1,0.8-5.9,2.3-8.5s3.6-4.7,6.2-6.2 S17.9,4,21,4c3.1,0,5.9,0.8,8.5,2.3s4.7,3.6,6.2,6.2C37.2,15.1,38,17.9,38,21z M25.7,30.6c0,0.3-0.1,0.5-0.2,0.6 c-0.1,0.2-0.3,0.2-0.6,0.2h-1.5c-0.2,0-0.4-0.1-0.6-0.2c-0.1-0.2-0.2-0.4-0.2-0.6v-19c0-0.3,0.1-0.5,0.2-0.6 c0.1-0.2,0.3-0.2,0.6-0.2h1.5c0.2,0,0.4,0.1,0.6,0.2c0.1,0.2,0.2,0.4,0.2,0.6V30.6z M19.6,30.6c0,0.3-0.1,0.5-0.2,0.6 c-0.1,0.2-0.3,0.2-0.6,0.2h-1.5c-0.2,0-0.4-0.1-0.6-0.2c-0.1-0.2-0.2-0.4-0.2-0.6v-19c0-0.3,0.1-0.5,0.2-0.6 c0.1-0.2,0.3-0.2,0.6-0.2h1.5c0.2,0,0.4,0.1,0.6,0.2c0.1,0.2,0.2,0.4,0.2,0.6V30.6z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 657:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath d='M35.6,21c0-2.6-0.7-5.1-2-7.3s-3.1-4-5.3-5.3s-4.7-2-7.3-2s-5.1,0.7-7.3,2s-4,3.1-5.3,5.3s-2,4.7-2,7.3s0.7,5.1,2,7.3 s3.1,4,5.3,5.3s4.7,2,7.3,2s5.1-0.7,7.3-2s4-3.1,5.3-5.3S35.6,23.6,35.6,21z M38,21c0,3.1-0.8,5.9-2.3,8.5c-1.5,2.6-3.6,4.7-6.2,6.2 C26.9,37.2,24.1,38,21,38c-3.1,0-5.9-0.8-8.5-2.3c-2.6-1.5-4.7-3.6-6.2-6.2S4,24.1,4,21c0-3.1,0.8-5.9,2.3-8.5s3.6-4.7,6.2-6.2 S17.9,4,21,4c3.1,0,5.9,0.8,8.5,2.3s4.7,3.6,6.2,6.2C37.2,15.1,38,17.9,38,21z M28.9,21.1c0,0.4-0.1,0.7-0.4,0.9l-9.1,9.1 c-0.3,0.3-0.6,0.4-0.9,0.4s-0.7-0.1-0.9-0.4c-0.3-0.3-0.4-0.6-0.4-0.9V12c0-0.4,0.1-0.7,0.4-0.9c0.3-0.3,0.6-0.4,0.9-0.4 s0.7,0.1,0.9,0.4l9.1,9.1C28.8,20.5,28.9,20.8,28.9,21.1z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 658:
/***/ (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' width='42.5' height='42.5'%3E %3Cstyle type='text/css'%3E .st0%7Bfill:%23E4003A;%7D %3C/style%3E %3Cpath class='st0' 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.4 v-1.3c0-0.5-0.2-1-0.6-1.4s-0.8-0.6-1.4-0.6H8.5c-0.5,0-1,0.2-1.4,0.6s-0.5,1-0.5,1.5v19.3c0,0.5,0.2,1,0.6,1.4s0.8,0.6,1.4,0.6H33 c0.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\""

/***/ }),

/***/ 659:
/***/ (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' width='42.5' height='42.5'%3E %3Cstyle type='text/css'%3E .st0%7Bfill:%23E4003A;%7D %3C/style%3E %3Cpath id='Icon_FileManager' class='st0' d='M37.9,23.2c0-0.5-0.4-0.7-1.1-0.7H14.9c-0.5,0-1.1,0.1-1.7,0.4c-0.6,0.3-1.1,0.6-1.4,1.1 l-5.9,7.3c-0.2,0.3-0.4,0.6-0.4,0.8c0,0.5,0.4,0.7,1.1,0.7h21.9c0.5,0,1.1-0.1,1.7-0.4c0.6-0.3,1.1-0.7,1.4-1.1l5.9-7.3 C37.7,23.7,37.9,23.4,37.9,23.2z M14.9,19.9h15.5v-3.2c0-0.5-0.2-1-0.6-1.4s-0.8-0.6-1.4-0.6H16.8c-0.5,0-1-0.2-1.4-0.6 c-0.4-0.4-0.6-0.8-0.6-1.4v-1.3c0-0.5-0.2-1-0.6-1.4S13.5,9.6,13,9.6H6.5c-0.5,0-1,0.2-1.4,0.6S4.6,11,4.6,11.5v17.2l5.2-6.3 c0.6-0.7,1.4-1.3,2.3-1.8C13,20.1,14,19.9,14.9,19.9z M40.4,23.2c0,0.8-0.3,1.6-0.9,2.4l-5.9,7.3c-0.6,0.7-1.4,1.3-2.3,1.8 c-1,0.5-1.9,0.7-2.8,0.7h-22c-1.2,0-2.3-0.4-3.2-1.3S2,32.1,2,30.8V11.5c0-1.2,0.4-2.3,1.3-3.2S5.3,7,6.5,7H13 c1.2,0,2.3,0.4,3.2,1.3c0.9,0.9,1.3,1.9,1.3,3.2v0.6h11c1.2,0,2.3,0.4,3.2,1.3c0.9,0.9,1.3,1.9,1.3,3.2v3.2h3.9c0.7,0,1.4,0.2,2,0.5 s1.1,0.8,1.3,1.4C40.3,22.2,40.4,22.7,40.4,23.2z'/%3E %3C/svg%3E\""

/***/ }),

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

module.exports = "\"data:image/svg+xml,%3C?xml version='1.0' encoding='utf-8'?%3E %3C!-- Generator: Adobe Illustrator 23.0.1, 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.52 42.52' style='enable-background:new 0 0 42.52 42.52;' xml:space='preserve' width='42.52' height='42.52'%3E %3Cstyle type='text/css'%3E .st0%7Bfill:none;stroke:%23000000;stroke-width:2;stroke-miterlimit:10;%7D %3C/style%3E %3Cpath class='st0' d='M22.93,37.06c0.14,1.54-0.99,2.9-2.53,3.05c-1.42,0.13-2.68-0.82-2.99-2.17c-0.03-0.12-0.05-0.24-0.06-0.36 l-0.35-3.74c-1.41-0.44-2.75-1.1-3.95-1.94l-2.35,3.16c-0.92,1.24-2.67,1.5-3.92,0.58c-0.56-0.42-0.92-1-1.06-1.63 c-0.17-0.77-0.02-1.6,0.48-2.29l2.94-3.96c-0.8-1.3-1.42-2.74-1.77-4.31c-0.07-0.3-0.11-0.6-0.15-0.9l-2.38,0.3 c-1.44,0.18-2.77-0.77-3.08-2.16c-0.02-0.09-0.04-0.18-0.05-0.27c-0.19-1.53,0.9-2.93,2.43-3.13l3.32-0.41 c0.04-0.16,0.07-0.32,0.12-0.47l-3.83-2.08c-0.74-0.4-1.22-1.09-1.39-1.85c-0.14-0.64-0.07-1.33,0.27-1.95 c0.74-1.36,2.44-1.86,3.8-1.12l3.76,2.04c1.19-1.47,2.68-2.72,4.41-3.62l-0.28-3.06c-0.14-1.54,0.99-2.9,2.53-3.05 c1.54-0.14,2.9,1.01,3.05,2.53l0.18,2c1.61-0.12,3.2,0.04,4.7,0.44l2.38-3.21c0.92-1.24,2.68-1.5,3.92-0.58 c1.24,0.92,1.5,2.68,0.57,3.92l-1.79,2.41c1.51,1.18,2.77,2.68,3.71,4.41l2.87-0.35c1.53-0.19,2.94,0.91,3.12,2.43 c0.19,1.54-0.9,2.93-2.43,3.12l-1.92,0.24c0.17,1.94-0.06,3.85-0.64,5.63l4.73,2.57c1.36,0.74,1.86,2.44,1.12,3.8 c-0.74,1.36-2.44,1.86-3.8,1.12l-4.81-2.62c-1.91,2.21-4.5,3.86-7.56,4.55c-0.53,0.12-1.06,0.2-1.59,0.26L22.93,37.06L22.93,37.06z M17.41,16.57c-2.21,0-4.01,1.79-4.01,4.01s1.79,4.01,4.01,4.01s4.01-1.79,4.01-4.01S19.63,16.57,17.41,16.57z M25.83,22.55 c-1.64,0-2.97,1.33-2.97,2.97s1.33,2.97,2.97,2.97s2.97-1.33,2.97-2.97S27.47,22.55,25.83,22.55z M24.54,13.01 c-1.14,0-2.07,0.93-2.07,2.07s0.93,2.07,2.07,2.07s2.07-0.93,2.07-2.07S25.69,13.01,24.54,13.01z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 661:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath d='M34.1,11.2l2.4,22c-1.3,0-2.7-0.3-3.9-1c-2-1.1-4.1-1.6-6-1.6c-2.3,0-4.2,0.9-5.7,2.6c-1.5-1.7-3.4-2.6-5.7-2.6 c-2,0-4,0.5-6,1.6c-1.3,0.7-2.6,1-3.9,1H5l2.4-22C9.7,9.7,12.1,9,14.8,9c2.4,0,4.4,0.6,5.9,1.8C22.3,9.6,24.3,9,26.7,9 C29.3,9,31.8,9.7,34.1,11.2z M26.5,28.3c1.3,0,2.5,0.2,3.6,0.5s2.4,0.9,4,1.6l-1.9-17.7c-1.8-0.9-3.6-1.4-5.7-1.4 c-2.3,0-4.2,0.8-5.7,2.4c-1.5-1.6-3.5-2.4-5.7-2.4c-2,0-3.9,0.5-5.7,1.4L7.4,30.4c1.1-0.5,1.9-0.9,2.5-1.1c0.6-0.3,1.4-0.5,2.3-0.7 c0.9-0.2,1.8-0.3,2.7-0.3c2.1,0,4,0.6,5.7,1.9C22.5,28.9,24.4,28.3,26.5,28.3z M27.1,26.5L26.2,13c-2.2,0-4,0.9-5.5,2.7 C19.2,13.9,17.3,13,15,13c-1.8,0-2.6,0.4-4.2,1.1L9.2,28.2c1.3-0.6,1.4-1,2.4-1.3s2.2-0.4,3.4-0.4c2.1,0,4.1,0.6,5.7,1.8 c1.8-1.2,3.7-1.8,5.7-1.8L27.1,26.5z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 662:
/***/ (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__(663);
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!./Node.css", function() {
			var newContent = require("!!../../Tinebase/js/node_modules/css-loader/index.js!./Node.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(); });
}

/***/ }),

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

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


// module
exports.push([module.i, "/*\n * Tine 2.0\n *\n * @license      http://www.gnu.org/licenses/agpl.html AGPL Version 3\n * @author       Michael Spahn <m.spahn@metaways.de>\n * @copyright    Copyright (c) 2018 Metaways Infosystems GmbH (http://www.metaways.de)\n *\n */\n\n.action_edit_file,\n.t-contenttype-node .action_edit_file {\n    background-image:url(" + __webpack_require__(664) + ") !important;\n}\n\n.t-contenttype-node .action_add {\n    background-image:url(" + __webpack_require__(665) + ") !important;\n}\n", ""]);

// exports


/***/ }),

/***/ 664:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath id='bearbeiten' d='M9.8,18.1H7.2V8.1c0-0.5,0.4-0.8,1-0.8h7.6c0.3,0,0.7,0.2,0.8,0.4l1.4,2h17c0.5,0,1,0.4,1,0.8v7.7h-2.8 v-5.8H9.8V18.1z M38,19.3c-0.1-0.1-0.3-0.2-0.5-0.2h-6.2l0,2.8h2.9c0.2,0,0.4,0.1,0.5,0.2c0.1,0.1,0.2,0.3,0.2,0.5L33,31.8 c-0.1,0.3-0.3,0.5-0.7,0.5l-21.5,0c-0.3,0-0.6-0.2-0.7-0.5l-1.8-9.2c0-0.2,0-0.3,0.2-0.5C8.6,22,8.8,21.9,9,21.9h3.8l0-2.8H5.7 c-0.2,0-0.4,0.1-0.5,0.2C5,19.4,5,19.6,5,19.8l2.7,14.4c0.1,0.3,0.3,0.5,0.7,0.5h26.3c0.4,0,0.6-0.2,0.7-0.5l2.7-14.4 C38.2,19.6,38.1,19.4,38,19.3z M24.3,24.9c-0.7,0.7-1.5,1-2.4,1s-1.8-0.3-2.4-1c-0.7-0.7-1-1.5-1-2.4s0.3-1.8,1-2.4 c0.7-0.7,1.5-1,2.4-1s1.8,0.3,2.4,1c0.7,0.7,1,1.5,1,2.4S25,24.2,24.3,24.9z M29.9,21.1c-0.1-0.1-0.1-0.1-0.2-0.1l-1.9-0.3 c-0.1-0.3-0.2-0.7-0.4-1c0.1-0.2,0.3-0.4,0.6-0.7s0.4-0.6,0.5-0.7c0.1-0.1,0.1-0.2,0.1-0.2c0-0.1,0-0.2-0.1-0.2 c-0.3-0.4-0.8-1-1.7-1.8c-0.1-0.1-0.2-0.1-0.3-0.1c-0.1,0-0.2,0-0.3,0.1L24.7,17c-0.3-0.1-0.6-0.3-0.9-0.4l-0.3-1.9 c0-0.1,0-0.2-0.1-0.2c-0.1-0.1-0.2-0.1-0.3-0.1h-2.3c-0.2,0-0.3,0.1-0.4,0.3c-0.1,0.4-0.2,1-0.3,2c-0.3,0.1-0.7,0.2-1,0.4l-1.5-1.1 c-0.1-0.1-0.2-0.1-0.3-0.1c-0.2,0-0.5,0.3-1,0.8s-0.9,0.9-1,1.1c-0.1,0.1-0.1,0.2-0.1,0.2c0,0.1,0,0.2,0.1,0.3 c0.5,0.6,0.8,1.1,1.1,1.5c-0.2,0.3-0.3,0.6-0.4,1l-2,0.3C14,20.9,14,21,13.9,21c-0.1,0.1-0.1,0.2-0.1,0.2v2.3c0,0.1,0,0.2,0.1,0.2 C14,23.9,14,24,14.1,24l1.9,0.3c0.1,0.3,0.2,0.7,0.4,1c-0.1,0.2-0.3,0.4-0.6,0.7c-0.3,0.3-0.4,0.6-0.5,0.7c-0.1,0.1-0.1,0.2-0.1,0.2 c0,0.1,0,0.2,0.1,0.2c0.3,0.4,0.9,1,1.7,1.8c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.2,0,0.3-0.1l1.5-1.1c0.3,0.1,0.6,0.3,0.9,0.4l0.3,1.9 c0,0.1,0,0.2,0.1,0.2s0.2,0.1,0.3,0.1h2.3c0.2,0,0.3-0.1,0.4-0.3c0.1-0.4,0.2-1,0.3-2c0.3-0.1,0.7-0.2,1-0.4l1.5,1.1 c0.1,0.1,0.2,0.1,0.3,0.1c0.2,0,0.5-0.2,1-0.7c0.5-0.5,0.9-0.9,1-1.1c0.1-0.1,0.1-0.2,0.1-0.2s0-0.2-0.1-0.3 c-0.5-0.6-0.9-1.1-1.1-1.5c0.1-0.3,0.3-0.6,0.4-1l2-0.3c0.1,0,0.2-0.1,0.2-0.1c0.1-0.1,0.1-0.2,0.1-0.2v-2.3 C30,21.2,30,21.2,29.9,21.1z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 665:
/***/ (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' width='42.5' height='42.5'%3E %3Cpath d='M9.8,18.1H7.2V8.1c0-0.5,0.4-0.8,1-0.8h7.6c0.3,0,0.7,0.2,0.8,0.4l1.4,2h17c0.5,0,1,0.4,1,0.8v7.7h-2.8v-5.8H9.8V18.1z M38,19.3c-0.1-0.1-0.3-0.2-0.5-0.2h-9.1l3,2.8h2.9c0.2,0,0.4,0.1,0.5,0.2c0.1,0.1,0.2,0.3,0.2,0.5L33,31.8 c-0.1,0.3-0.3,0.5-0.7,0.5l-21.5,0c-0.3,0-0.6-0.2-0.7-0.5l-1.8-9.2c0-0.2,0-0.3,0.2-0.5C8.6,22,8.8,21.9,9,21.9h3.8l2.9-2.8h-10 c-0.2,0-0.4,0.1-0.5,0.2C5,19.4,5,19.6,5,19.8l2.7,14.4c0.1,0.3,0.3,0.5,0.7,0.5h26.3c0.4,0,0.6-0.2,0.7-0.5l2.7-14.4 C38.2,19.6,38.1,19.4,38,19.3z M29.1,22.1l-6.2-6.2c-0.2-0.2-0.4-0.3-0.6-0.3s-0.5,0.1-0.6,0.3l-6.2,6.2c-0.3,0.3-0.4,0.6-0.2,1 c0.2,0.4,0.4,0.6,0.8,0.6h3.6v6.2c0,0.2,0.1,0.4,0.3,0.6c0.2,0.2,0.4,0.3,0.6,0.3H24c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.3-0.4,0.3-0.6 v-6.2h3.6c0.4,0,0.7-0.2,0.8-0.6C29.4,22.7,29.3,22.4,29.1,22.1z'/%3E %3C/svg%3E\""

/***/ }),

/***/ 89:
/***/ (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' width='42.5' height='42.5'%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\""

/***/ })

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