mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-17 22:47:59 +00:00
* textcolor: fixed plugin bugs, added translation for zh * image: fixed default.jpg src bug * added 'ru' support for seaf edit * rm aloha-0.22.3 and ununsed files in aloha-0.22.7
526 lines
14 KiB
JavaScript
Executable File
526 lines
14 KiB
JavaScript
Executable File
/* jquery.aloha.js is part of Aloha Editor project http://aloha-editor.org
|
|
*
|
|
* Aloha Editor is a WYSIWYG HTML5 inline editing library and editor.
|
|
* Copyright (c) 2010-2012 Gentics Software GmbH, Vienna, Austria.
|
|
* Contributors http://aloha-editor.org/contribution.php
|
|
*
|
|
* Aloha Editor is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* Aloha Editor is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* As an additional permission to the GNU GPL version 2, you may distribute
|
|
* non-source (e.g., minimized or compacted) forms of the Aloha-Editor
|
|
* source code without the copy of the GNU GPL normally required,
|
|
* provided you include this license notice and a URL through which
|
|
* recipients can access the Corresponding Source.
|
|
*/
|
|
/**
|
|
* IMPORTANT!
|
|
* Don't add any more custom jquery extensions here.
|
|
* Instead use the define(...) mechanism to define a module and to
|
|
* import it where you need it.
|
|
*/
|
|
define([
|
|
'aloha/core',
|
|
'aloha/selection',
|
|
'jquery',
|
|
'aloha/console'
|
|
], function (
|
|
Aloha,
|
|
Selection,
|
|
jQuery,
|
|
console
|
|
) {
|
|
'use strict';
|
|
|
|
var XMLSerializer = window.XMLSerializer;
|
|
|
|
/**
|
|
* jQuery between Extension
|
|
*
|
|
* insert either html code, a dom object OR a jQuery object inside of an existing text node.
|
|
* if the chained jQuery object is not a text node, nothing will happen.
|
|
*
|
|
* @param content HTML Code, DOM object or jQuery object to be inserted
|
|
* @param offset character offset from the start where the content should be inserted
|
|
*/
|
|
jQuery.fn.between = function (content, offset) {
|
|
var offSize, fullText;
|
|
|
|
if (this[0].nodeType !== 3) {
|
|
// we are not in a text node, just insert the element at the corresponding position
|
|
offSize = this.children().size();
|
|
if (offset > offSize) {
|
|
offset = offSize;
|
|
}
|
|
if (offset <= 0) {
|
|
this.prepend(content);
|
|
} else {
|
|
this.children().eq(offset - 1).after(content);
|
|
}
|
|
} else {
|
|
// we are in a text node so we have to split it at the correct position
|
|
if (offset <= 0) {
|
|
this.before(content);
|
|
} else if (offset >= this[0].length) {
|
|
this.after(content);
|
|
} else {
|
|
fullText = this[0].data;
|
|
this[0].data = fullText.substring(0, offset);
|
|
this.after(fullText.substring(offset, fullText.length));
|
|
this.after(content);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Make the object contenteditable. Care about browser version (name of contenteditable attribute depends on it)
|
|
*/
|
|
jQuery.fn.contentEditable = function (b) {
|
|
// ie does not understand contenteditable but contentEditable
|
|
// contentEditable is not xhtml compatible.
|
|
var $el = jQuery(this);
|
|
var ce = 'contenteditable';
|
|
|
|
// Check
|
|
if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) == 7) {
|
|
ce = 'contentEditable';
|
|
}
|
|
|
|
if (typeof b === 'undefined') {
|
|
|
|
// For chrome use this specific attribute. The old ce will only
|
|
// return 'inherit' for nested elements of a contenteditable.
|
|
// The isContentEditable is a w3c standard compliant property which works in IE7,8,FF36+, Chrome 12+
|
|
if (typeof $el[0] === 'undefined') {
|
|
console.warn('The jquery object did not contain any valid elements.'); // die silent
|
|
return undefined;
|
|
}
|
|
if (typeof $el[0].isContentEditable === 'undefined') {
|
|
console.warn('Could not determine whether the is editable or not. I assume it is.');
|
|
return true;
|
|
}
|
|
|
|
return $el[0].isContentEditable;
|
|
}
|
|
|
|
if (b === '') {
|
|
$el.removeAttr(ce);
|
|
} else {
|
|
if (b && b !== 'false') {
|
|
b = 'true';
|
|
} else {
|
|
b = 'false';
|
|
}
|
|
$el.attr(ce, b);
|
|
}
|
|
|
|
return $el;
|
|
};
|
|
|
|
/**
|
|
* jQuery Aloha Plugin.
|
|
*
|
|
* Makes the elements in a jQuery selection set Aloha editables.
|
|
*
|
|
* @return jQuery container of holding DOM elements that have been
|
|
* aloha()fied.
|
|
* @api
|
|
*/
|
|
jQuery.fn.aloha = function () {
|
|
var $elements = this;
|
|
Aloha.bind('aloha-plugins-loaded', function () {
|
|
$elements.each(function (_, elem) {
|
|
if (!Aloha.isEditable(elem)) {
|
|
new Aloha.Editable(jQuery(elem)).init();
|
|
}
|
|
});
|
|
});
|
|
return $elements;
|
|
};
|
|
|
|
/**
|
|
* jQuery destroy elements as editable
|
|
*
|
|
* destroy all mached elements editable capabilities
|
|
* @return jQuery object for the matched elements
|
|
* @api
|
|
*/
|
|
jQuery.fn.mahalo = function () {
|
|
return this.each(function () {
|
|
if (Aloha.isEditable(this)) {
|
|
Aloha.getEditableById(jQuery(this).attr('id')).destroy();
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* jQuery Extension
|
|
* new Event which is triggered whenever a selection (length >= 0) is made in
|
|
* an Aloha Editable element
|
|
*/
|
|
jQuery.fn.contentEditableSelectionChange = function (callback) {
|
|
var that = this;
|
|
|
|
// update selection when keys are pressed
|
|
this.keyup(function (event) {
|
|
var rangeObject = Selection.getRangeObject();
|
|
callback(event);
|
|
});
|
|
|
|
// update selection on doubleclick (especially important for the first automatic selection, when the Editable is not active yet, but is at the same time activated as the selection occurs
|
|
this.dblclick(function (event) {
|
|
callback(event);
|
|
});
|
|
|
|
// update selection when text is selected
|
|
this.mousedown(function (event) {
|
|
// remember that a selection was started
|
|
that.selectionStarted = true;
|
|
});
|
|
|
|
jQuery(document).mouseup(function (event) {
|
|
Selection.eventOriginalTarget = that;
|
|
if (that.selectionStarted) {
|
|
callback(event);
|
|
}
|
|
Selection.eventOriginalTarget = false;
|
|
that.selectionStarted = false;
|
|
});
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Fetch the outerHTML of an Element
|
|
* @version 1.0.0
|
|
* @date February 01, 2011
|
|
* @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle}
|
|
* @author Benjamin Arthur Lupton {@link http://balupton.com}
|
|
* @copyright 2011 Benjamin Arthur Lupton {@link http://balupton.com}
|
|
* @license MIT License {@link http://creativecommons.org/licenses/MIT/}
|
|
* @return {String} outerHtml
|
|
*/
|
|
jQuery.fn.outerHtml = jQuery.fn.outerHtml || function () {
|
|
var $el = jQuery(this),
|
|
el = $el.get(0);
|
|
if (typeof el.outerHTML != 'undefined') {
|
|
return el.outerHTML;
|
|
}
|
|
try {
|
|
// Gecko-based browsers, Safari, Opera.
|
|
return (new XMLSerializer()).serializeToString(el);
|
|
} catch (e) {
|
|
try {
|
|
// Internet Explorer.
|
|
return el.xml;
|
|
} catch (e2) {}
|
|
}
|
|
};
|
|
|
|
jQuery.fn.zap = function () {
|
|
return this.each(function () {
|
|
jQuery(this.childNodes).insertBefore(this);
|
|
}).remove();
|
|
};
|
|
|
|
jQuery.fn.textNodes = function (excludeBreaks, includeEmptyTextNodes) {
|
|
var ret = [],
|
|
doSomething = function (el) {
|
|
var i, childLength;
|
|
if ((el.nodeType === 3 && jQuery.trim(el.data) && !includeEmptyTextNodes) || (el.nodeType === 3 && includeEmptyTextNodes) || (el.nodeName == "BR" && !excludeBreaks)) {
|
|
ret.push(el);
|
|
} else {
|
|
for (i = 0, childLength = el.childNodes.length; i < childLength; ++i) {
|
|
doSomething(el.childNodes[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
doSomething(this[0]);
|
|
|
|
return jQuery(ret);
|
|
};
|
|
|
|
/**
|
|
* extendObjects is like jQuery.extend, but it does not extend arrays
|
|
*/
|
|
jQuery.extendObjects = jQuery.fn.extendObjects = function (arg1, arg2) {
|
|
var options, name, src, copy, copyIsArray, clone,
|
|
start = 1,
|
|
target = arg1 || {},
|
|
length = arguments.length,
|
|
deep = false,
|
|
i;
|
|
|
|
|
|
// Handle a deep copy situation
|
|
if (typeof target === "boolean") {
|
|
deep = target;
|
|
target = arg2 || {};
|
|
// skip the boolean and the target
|
|
start = 2;
|
|
}
|
|
|
|
// Handle case when target is a string or something (possible in deep copy)
|
|
if (typeof target !== "object" && !jQuery.isFunction(target)) {
|
|
target = {};
|
|
}
|
|
|
|
// extend jQuery itself if only one argument is passed
|
|
if (length === start) {
|
|
target = this;
|
|
--start;
|
|
}
|
|
|
|
for (i = start; i < length; i++) {
|
|
// Only deal with non-null/undefined values
|
|
if ((options = arguments[i]) != null) {
|
|
// Extend the base object
|
|
for (name in options) {
|
|
if (options.hasOwnProperty(name)) {
|
|
|
|
src = target[name];
|
|
copy = options[name];
|
|
|
|
// Prevent never-ending loop
|
|
if (target === copy) {
|
|
continue;
|
|
}
|
|
|
|
// Recurse if we're merging plain objects or arrays
|
|
if (deep && copy && (jQuery.isPlainObject(copy) || true === (copyIsArray = jQuery.isArray(copy)))) {
|
|
if (copyIsArray) {
|
|
copyIsArray = false;
|
|
clone = src && jQuery.isArray(src) ? src : [];
|
|
|
|
} else {
|
|
clone = src && jQuery.isPlainObject(src) ? src : {};
|
|
}
|
|
|
|
// Never move original objects, clone them
|
|
if (jQuery.isArray(copy)) {
|
|
// don't extend arrays
|
|
target[name] = copy;
|
|
} else {
|
|
target[name] = jQuery.extendObjects(deep, clone, copy);
|
|
}
|
|
|
|
// Don't bring in undefined values
|
|
} else if (copy !== undefined) {
|
|
target[name] = copy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return the modified object
|
|
return target;
|
|
};
|
|
|
|
/*
|
|
* jQuery Hotkeys Plugin
|
|
* Copyright 2010, John Resig
|
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
*
|
|
* Based upon the plugin by Tzury Bar Yochay:
|
|
* http://github.com/tzuryby/hotkeys
|
|
*
|
|
* Original idea by:
|
|
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
|
*/
|
|
|
|
jQuery.hotkeys = {
|
|
version: "0.8",
|
|
|
|
specialKeys: {
|
|
8: "backspace",
|
|
9: "tab",
|
|
13: "return",
|
|
16: "shift",
|
|
17: "ctrl",
|
|
18: "alt",
|
|
19: "pause",
|
|
20: "capslock",
|
|
27: "esc",
|
|
32: "space",
|
|
33: "pageup",
|
|
34: "pagedown",
|
|
35: "end",
|
|
36: "home",
|
|
37: "left",
|
|
38: "up",
|
|
39: "right",
|
|
40: "down",
|
|
45: "insert",
|
|
46: "del",
|
|
96: "0",
|
|
97: "1",
|
|
98: "2",
|
|
99: "3",
|
|
100: "4",
|
|
101: "5",
|
|
102: "6",
|
|
103: "7",
|
|
104: "8",
|
|
105: "9",
|
|
106: "*",
|
|
107: "+",
|
|
109: "-",
|
|
110: ".",
|
|
111: "/",
|
|
112: "f1",
|
|
113: "f2",
|
|
114: "f3",
|
|
115: "f4",
|
|
116: "f5",
|
|
117: "f6",
|
|
118: "f7",
|
|
119: "f8",
|
|
120: "f9",
|
|
121: "f10",
|
|
122: "f11",
|
|
123: "f12",
|
|
144: "numlock",
|
|
145: "scroll",
|
|
191: "/",
|
|
224: "meta"
|
|
},
|
|
|
|
shiftNums: {
|
|
"`": "~",
|
|
"1": "!",
|
|
"2": "@",
|
|
"3": "#",
|
|
"4": "$",
|
|
"5": "%",
|
|
"6": "^",
|
|
"7": "&",
|
|
"8": "*",
|
|
"9": "(",
|
|
"0": ")",
|
|
"-": "_",
|
|
"=": "+",
|
|
";": ": ",
|
|
"'": "\"",
|
|
",": "<",
|
|
".": ">",
|
|
"/": "?",
|
|
"\\": "|"
|
|
}
|
|
};
|
|
|
|
function applyKeyHandler(handler, context, args, event) {
|
|
// Don't fire in text-accepting inputs that we didn't directly bind to
|
|
if (context !== event.target && (/textarea|input|select/i.test(event.target.nodeName) || event.target.type === "text")) {
|
|
return;
|
|
}
|
|
return handler.apply(context, args);
|
|
}
|
|
|
|
function keyHandler(handleObj) {
|
|
var origHandler, keys, handle, i;
|
|
|
|
// Only care when a possible input has been specified
|
|
if (typeof handleObj.data !== "string") {
|
|
return;
|
|
}
|
|
|
|
origHandler = handleObj.handler;
|
|
keys = handleObj.data.toLowerCase().split(" ");
|
|
handle = {};
|
|
|
|
for (i = 0; i < keys.length; i++) {
|
|
handle[keys[i]] = true;
|
|
}
|
|
|
|
handleObj.handler = function (event) {
|
|
// The original comment that was added with this condition says:
|
|
// "Don't fire in contentEditable true elements"
|
|
// But this is incorrect.
|
|
// What this condition does is it skips hotkey events for
|
|
// any target unless it is directly bound.
|
|
// The condition event.target.contentEditable !== true will
|
|
// always be true, because contentEditable is a string
|
|
// attribute that is never strictly equal true.
|
|
//if (this !== event.target && event.target.contentEditable !== true) {
|
|
//return;
|
|
//}
|
|
// Below is what this condition really does. Ideally, I'd
|
|
// like to remove this condition since it was not there in
|
|
// the original implementation by John Resig and it could
|
|
// interfere with other plugins, but when I removed it, I
|
|
// was unable to input any space characters into an
|
|
// editable.
|
|
// TODO figure out a way to safely remove this
|
|
if (this !== event.target) {
|
|
return;
|
|
}
|
|
|
|
// Keypress represents characters, not special keys
|
|
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[event.which],
|
|
modif = "",
|
|
character;
|
|
|
|
// check combinations (alt|ctrl|shift+anything)
|
|
if (event.altKey && special !== "alt") {
|
|
modif += "alt+";
|
|
}
|
|
|
|
if (event.ctrlKey && special !== "ctrl") {
|
|
modif += "ctrl+";
|
|
}
|
|
|
|
// TODO: Need to make sure this works consistently across platforms
|
|
if (event.metaKey && !event.ctrlKey && special !== "meta") {
|
|
modif += "meta+";
|
|
}
|
|
|
|
if (event.shiftKey && special !== "shift") {
|
|
modif += "shift+";
|
|
}
|
|
|
|
if (special) {
|
|
if (handle[modif + special]) {
|
|
return applyKeyHandler(origHandler, this, arguments, event);
|
|
}
|
|
} else {
|
|
character = String.fromCharCode(event.which).toLowerCase();
|
|
|
|
if (handle[modif + character]) {
|
|
return applyKeyHandler(origHandler, this, arguments, event);
|
|
}
|
|
|
|
if (handle[modif + jQuery.hotkeys.shiftNums[character]]) {
|
|
return applyKeyHandler(origHandler, this, arguments, event);
|
|
}
|
|
|
|
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
|
|
if (modif === "shift+") {
|
|
if (handle[jQuery.hotkeys.shiftNums[character]]) {
|
|
return applyKeyHandler(origHandler, this, arguments, event);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
jQuery.each(['keydown', 'keyup', 'keypress'], function () {
|
|
jQuery.event.special[this] = {
|
|
add: keyHandler
|
|
};
|
|
});
|
|
|
|
});
|