1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-17 22:47:59 +00:00
seahub/media/aloha-0.22.7/lib/aloha/jquery.aloha.js
llj 720ac28c22 [aloha] upgraded to 0.22.7 and added textcolor plugin
* 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
2013-01-15 14:48:04 +08:00

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