<commit_before>/**
 * FilePicker.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/*global tinymce:true */

/**
 * This class creates a file picker control.
 *
 * @class tinymce.ui.FilePicker
 * @extends tinymce.ui.ComboBox
 */
define("tinymce/ui/FilePicker", [
	"tinymce/ui/ComboBox",
	"tinymce/util/Tools",
	"tinymce/util/Arr",
	"tinymce/util/Fun",
	"tinymce/util/VK",
	"tinymce/content/LinkTargets"
], function(ComboBox, Tools, Arr, Fun, VK, LinkTargets) {
	"use strict";

	var history = {};
	var HISTORY_LENGTH = 5;

	var toMenuItems = function (targets) {
		return Tools.map(targets, function (target) {
			return {
				title: target.title,
				value: {
					title: target.title,
					url: target.url,
					attach: target.attach
				}
			};
		});
	};

	var isUniqueUrl = function (url, targets) {
		var foundTarget = Arr.find(targets, function (target) {
			return target.url === url;
		});

		return !foundTarget;
	};

	var createMenuItems = function (term, targets, fileType) {
		var separator = {title: '-'};

		var fromHistoryMenuItems = function (history) {
			var uniqueHistory = Arr.filter(history[fileType], function (url) {
				return isUniqueUrl(url, targets);
			});

			return Tools.map(uniqueHistory, function (url) {
				return {
					title: url,
					value: {
						title: url,
						url: url,
						attach: Fun.noop
					}
				};
			});
		};

		var fromMenuItems = function (type) {
			var filteredTargets = Arr.filter(targets, function (target) {
				return target.type == type;
			});

			return toMenuItems(filteredTargets);
		};

		var join = function (items) {
			return Arr.reduce(items, function (a, b) {
				var bothEmpty = a.length === 0 || b.length === 0;
				return bothEmpty ? a.concat(b) : a.concat(separator, b);
			}, []);
		};

		return join([
			filterByQuery(term, fromHistoryMenuItems(history)),
			filterByQuery(term, fromMenuItems('header')),
			filterByQuery(term, fromMenuItems('anchor'))
		]);
	};

	var addToHistory = function (url, fileType) {
		var items = history[fileType];

		if (items) {
			if (Arr.indexOf(items, url) === -1) {
				history[fileType] = items.slice(0, HISTORY_LENGTH).concat(url);
			}
		} else {
			history[fileType] = [url];
		}
	};

	var filterByQuery = function (term, menuItems) {
		var lowerCaseTerm = term.toLowerCase();
		var result = Tools.grep(menuItems, function (item) {
			return item.title.toLowerCase().indexOf(lowerCaseTerm) !== -1;
		});

		return result.length === 1 && result[0].title === term ? [] : result;
	};

	var setupAutoCompleteHandler = function (ctrl, bodyElm, fileType) {
		var autocomplete = function (term) {
			var linkTargets = LinkTargets.find(bodyElm);
			var menuItems = createMenuItems(term, linkTargets, fileType);
			ctrl.showAutoComplete(menuItems, term);
		};

		ctrl.on('autocomplete', function () {
			autocomplete(ctrl.value());
		});

		ctrl.on('selectitem', function (e) {
			var linkDetails = e.value;

			ctrl.value(linkDetails.url);

			if (fileType === 'image') {
				ctrl.fire('change', {meta: {alt: linkDetails.title, attach: linkDetails.attach}});
			} else {
				ctrl.fire('change', {meta: {text: linkDetails.title, attach: linkDetails.attach}});
			}

			ctrl.focus();
		});

		ctrl.on('click', function () {
			if (ctrl.value().length === 0) {
				autocomplete('');
			}
		});

		ctrl.on('PostRender', function () {
			ctrl.getRoot().on('submit', function (e) {
				if (!e.isDefaultPrevented()) {
					addToHistory(ctrl.value(), fileType);
				}
			});
		});
	};

	var statusToUiState = function (result) {
		var status = result.status, message = result.message;

		if (status === 'valid') {
			return {status: 'ok', message: message};
		} else if (status === 'unknown') {
			return {status: 'warn', message: message};
		} else if (status === 'invalid') {
			return {status: 'warn', message: message};
		} else {
			return {status: 'none', message: ''};
		}
	};

	var setupLinkValidatorHandler = function (ctrl, editorSettings, fileType) {
		var validatorHandler = editorSettings.filepicker_validator_handler;
		if (validatorHandler) {
			var validateUrl = function (url) {
				if (url.length === 0) {
					ctrl.statusLevel('none');
					return;
				}

				validatorHandler({
					url: url,
					type: fileType
				}, function (result) {
					var uiState = statusToUiState(result);

					ctrl.statusMessage(uiState.message);
					ctrl.statusLevel(uiState.status);
				});
			};

			ctrl.state.on('change:value', function (e) {
				validateUrl(e.value);
			});
		}
	};

	return ComboBox.extend({
		/**
		 * Constructs a new control instance with the specified settings.
		 *
		 * @constructor
		 * @param {Object} settings Name/value object with settings.
		 */
		init: function(settings) {
			var self = this, editor = tinymce.activeEditor, editorSettings = editor.settings;
			var actionCallback, fileBrowserCallback, fileBrowserCallbackTypes;
			var fileType = settings.filetype;

			settings.spellcheck = false;

			fileBrowserCallbackTypes = editorSettings.file_picker_types || editorSettings.file_browser_callback_types;
			if (fileBrowserCallbackTypes) {
				fileBrowserCallbackTypes = Tools.makeMap(fileBrowserCallbackTypes, /[, ]/);
			}

			if (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType]) {
				fileBrowserCallback = editorSettings.file_picker_callback;
				if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
					actionCallback = function() {
						var meta = self.fire('beforecall').meta;

						meta = Tools.extend({filetype: fileType}, meta);

						// file_picker_callback(callback, currentValue, metaData)
						fileBrowserCallback.call(
							editor,
							function(value, meta) {
								self.value(value).fire('change', {meta: meta});
							},
							self.value(),
							meta
						);
					};
				} else {
					// Legacy callback: file_picker_callback(id, currentValue, filetype, window)
					fileBrowserCallback = editorSettings.file_browser_callback;
					if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
						actionCallback = function() {
							fileBrowserCallback(
								self.getEl('inp').id,
								self.value(),
								fileType,
								window
							);
						};
					}
				}
			}

			if (actionCallback) {
				settings.icon = 'browse';
				settings.onaction = actionCallback;
			}

			self._super(settings);

			setupAutoCompleteHandler(self, editor.getBody(), fileType);
			setupLinkValidatorHandler(self, editorSettings, fileType);
		}
	});
});<commit_msg>TINY-572: added top/bottom anchors<commit_after>/**
 * FilePicker.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/*global tinymce:true */

/**
 * This class creates a file picker control.
 *
 * @class tinymce.ui.FilePicker
 * @extends tinymce.ui.ComboBox
 */
define("tinymce/ui/FilePicker", [
	"tinymce/ui/ComboBox",
	"tinymce/util/Tools",
	"tinymce/util/Arr",
	"tinymce/util/Fun",
	"tinymce/util/VK",
	"tinymce/content/LinkTargets"
], function(ComboBox, Tools, Arr, Fun, VK, LinkTargets) {
	"use strict";

	var history = {};
	var HISTORY_LENGTH = 5;

	var toMenuItem = function (target) {
		return {
			title: target.title,
			value: {
				title: target.title,
				url: target.url,
				attach: target.attach
			}
		};
	};

	var toMenuItems = function (targets) {
		return Tools.map(targets, toMenuItem);
	};

	var staticMenuItem = function (title, url) {
		return {
			title: title,
			value: {
				title: title,
				url: url,
				attach: Fun.noop
			}
		};
	};

	var isUniqueUrl = function (url, targets) {
		var foundTarget = Arr.find(targets, function (target) {
			return target.url === url;
		});

		return !foundTarget;
	};

	var createMenuItems = function (term, targets, fileType) {
		var separator = {title: '-'};

		var fromHistoryMenuItems = function (history) {
			var uniqueHistory = Arr.filter(history[fileType], function (url) {
				return isUniqueUrl(url, targets);
			});

			return Tools.map(uniqueHistory, function (url) {
				return {
					title: url,
					value: {
						title: url,
						url: url,
						attach: Fun.noop
					}
				};
			});
		};

		var fromMenuItems = function (type) {
			var filteredTargets = Arr.filter(targets, function (target) {
				return target.type == type;
			});

			return toMenuItems(filteredTargets);
		};

		var anchorMenuItems = function () {
			var menuItems = fromMenuItems('anchor');
			var top = staticMenuItem('<top>', '#top');
			var bottom = staticMenuItem('<bottom>', '#bottom');

			return [top].concat(menuItems).concat([bottom]);
		};

		var join = function (items) {
			return Arr.reduce(items, function (a, b) {
				var bothEmpty = a.length === 0 || b.length === 0;
				return bothEmpty ? a.concat(b) : a.concat(separator, b);
			}, []);
		};

		return join([
			filterByQuery(term, fromHistoryMenuItems(history)),
			filterByQuery(term, fromMenuItems('header')),
			filterByQuery(term, anchorMenuItems())
		]);
	};

	var addToHistory = function (url, fileType) {
		var items = history[fileType];

		if (url === "#top" || url === "#bottom") {
			return;
		}

		if (items) {
			if (Arr.indexOf(items, url) === -1) {
				history[fileType] = items.slice(0, HISTORY_LENGTH).concat(url);
			}
		} else {
			history[fileType] = [url];
		}
	};

	var filterByQuery = function (term, menuItems) {
		var lowerCaseTerm = term.toLowerCase();
		var result = Tools.grep(menuItems, function (item) {
			return item.title.toLowerCase().indexOf(lowerCaseTerm) !== -1;
		});

		return result.length === 1 && result[0].title === term ? [] : result;
	};

	var setupAutoCompleteHandler = function (ctrl, bodyElm, fileType) {
		var autocomplete = function (term) {
			var linkTargets = LinkTargets.find(bodyElm);
			var menuItems = createMenuItems(term, linkTargets, fileType);
			ctrl.showAutoComplete(menuItems, term);
		};

		ctrl.on('autocomplete', function () {
			autocomplete(ctrl.value());
		});

		ctrl.on('selectitem', function (e) {
			var linkDetails = e.value;

			ctrl.value(linkDetails.url);

			if (fileType === 'image') {
				ctrl.fire('change', {meta: {alt: linkDetails.title, attach: linkDetails.attach}});
			} else {
				ctrl.fire('change', {meta: {text: linkDetails.title, attach: linkDetails.attach}});
			}

			ctrl.focus();
		});

		ctrl.on('click', function () {
			if (ctrl.value().length === 0) {
				autocomplete('');
			}
		});

		ctrl.on('PostRender', function () {
			ctrl.getRoot().on('submit', function (e) {
				if (!e.isDefaultPrevented()) {
					addToHistory(ctrl.value(), fileType);
				}
			});
		});
	};

	var statusToUiState = function (result) {
		var status = result.status, message = result.message;

		if (status === 'valid') {
			return {status: 'ok', message: message};
		} else if (status === 'unknown') {
			return {status: 'warn', message: message};
		} else if (status === 'invalid') {
			return {status: 'warn', message: message};
		} else {
			return {status: 'none', message: ''};
		}
	};

	var setupLinkValidatorHandler = function (ctrl, editorSettings, fileType) {
		var validatorHandler = editorSettings.filepicker_validator_handler;
		if (validatorHandler) {
			var validateUrl = function (url) {
				if (url.length === 0) {
					ctrl.statusLevel('none');
					return;
				}

				validatorHandler({
					url: url,
					type: fileType
				}, function (result) {
					var uiState = statusToUiState(result);

					ctrl.statusMessage(uiState.message);
					ctrl.statusLevel(uiState.status);
				});
			};

			ctrl.state.on('change:value', function (e) {
				validateUrl(e.value);
			});
		}
	};

	return ComboBox.extend({
		/**
		 * Constructs a new control instance with the specified settings.
		 *
		 * @constructor
		 * @param {Object} settings Name/value object with settings.
		 */
		init: function(settings) {
			var self = this, editor = tinymce.activeEditor, editorSettings = editor.settings;
			var actionCallback, fileBrowserCallback, fileBrowserCallbackTypes;
			var fileType = settings.filetype;

			settings.spellcheck = false;

			fileBrowserCallbackTypes = editorSettings.file_picker_types || editorSettings.file_browser_callback_types;
			if (fileBrowserCallbackTypes) {
				fileBrowserCallbackTypes = Tools.makeMap(fileBrowserCallbackTypes, /[, ]/);
			}

			if (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType]) {
				fileBrowserCallback = editorSettings.file_picker_callback;
				if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
					actionCallback = function() {
						var meta = self.fire('beforecall').meta;

						meta = Tools.extend({filetype: fileType}, meta);

						// file_picker_callback(callback, currentValue, metaData)
						fileBrowserCallback.call(
							editor,
							function(value, meta) {
								self.value(value).fire('change', {meta: meta});
							},
							self.value(),
							meta
						);
					};
				} else {
					// Legacy callback: file_picker_callback(id, currentValue, filetype, window)
					fileBrowserCallback = editorSettings.file_browser_callback;
					if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
						actionCallback = function() {
							fileBrowserCallback(
								self.getEl('inp').id,
								self.value(),
								fileType,
								window
							);
						};
					}
				}
			}

			if (actionCallback) {
				settings.icon = 'browse';
				settings.onaction = actionCallback;
			}

			self._super(settings);

			setupAutoCompleteHandler(self, editor.getBody(), fileType);
			setupLinkValidatorHandler(self, editorSettings, fileType);
		}
	});
});
{'fraction_non_alphanumeric': 0.14761904761904762, 'fraction_numerical': 0.002813852813852814, 'mean_word_length': 3.39752538071066, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5918747', 'n_tokens_mistral': 5412, 'n_tokens_neox': 4348, 'n_words': 939}