mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-18 06:57:52 +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
302 lines
9.8 KiB
JavaScript
302 lines
9.8 KiB
JavaScript
/* ephemera.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.
|
|
*/
|
|
define([
|
|
'jquery',
|
|
'util/maps',
|
|
'util/strings',
|
|
'util/browser'
|
|
], function (
|
|
$,
|
|
Maps,
|
|
Strings,
|
|
Browser
|
|
) {
|
|
'use strict';
|
|
|
|
var spacesRx = /\s+/;
|
|
var attrRegex = /\s([^\/<>\s=]+)(?:=(?:"[^"]*"|'[^']*'|[^>\/\s]+))?/g;
|
|
|
|
/**
|
|
* Like insertBefore, inserts firstChild into parent before
|
|
* refChild, except also inserts all the following siblings of
|
|
* firstChild.
|
|
*/
|
|
function moveNextAll(parent, firstChild, refChild) {
|
|
while (firstChild) {
|
|
var nextChild = firstChild.nextSibling;
|
|
parent.insertBefore(firstChild, refChild);
|
|
firstChild = nextChild;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used to serialize outerHTML of DOM elements in older (pre-HTML5) Gecko,
|
|
* Safari, and Opera browsers.
|
|
*
|
|
* Beware that XMLSerializer generates an XHTML string (<div class="team" />
|
|
* instead of <div class="team"></div>). It is noted here:
|
|
* http://stackoverflow.com/questions/1700870/how-do-i-do-outerhtml-in-firefox
|
|
* that some browsers (like older versions of Firefox) have problems with
|
|
* XMLSerializer, and an alternative, albeit more expensive option, is
|
|
* described.
|
|
*
|
|
* @type {XMLSerializer|null}
|
|
*/
|
|
var Serializer = window.XMLSerializer && new window.XMLSerializer();
|
|
|
|
/**
|
|
* Gets the serialized HTML that describes the given DOM element and its
|
|
* innerHTML.
|
|
*
|
|
* Polyfill for older versions of Gecko, Safari, and Opera browsers.
|
|
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=92264 for background.
|
|
*
|
|
* @param {HTMLElement} node DOM Element.
|
|
* @return {String}
|
|
*/
|
|
function outerHtml(node) {
|
|
var html = node.outerHTML;
|
|
if (typeof html !== 'undefined') {
|
|
return html;
|
|
}
|
|
try {
|
|
return Serializer ? Serializer.serializeToString(node) : node.xml;
|
|
} catch (e) {
|
|
return node.xml;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves the names of all attributes from the given elmenet.
|
|
*
|
|
* Correctly handles the case that IE7 and IE8 have approx 70-90
|
|
* default attributes on each and every element.
|
|
*
|
|
* This implementation does not iterate over the elem.attributes
|
|
* property since that is much slower on IE7 (even when
|
|
* checking the attrNode.specified property). Instead it parses the
|
|
* HTML of the element. For elements with few attributes the
|
|
* performance on IE7 is improved by an order of magnitued.
|
|
*
|
|
* On IE7, when you clone a <button disabled="disabled"/> or an
|
|
* <input checked="checked"/> element the boolean properties will
|
|
* not be set on the cloned node. We choose the speed optimization
|
|
* over correctness in this case. The dom-to-xhtml plugin has a
|
|
* workaround for this case.
|
|
*/
|
|
function attrNames(elem) {
|
|
var names = [];
|
|
var html = outerHtml(elem.cloneNode(false));
|
|
var match;
|
|
while (null != (match = attrRegex.exec(html))) {
|
|
names.push(match[1]);
|
|
}
|
|
return names;
|
|
}
|
|
|
|
/**
|
|
* Gets the attributes of the given element.
|
|
*
|
|
* See attrNames() for an edge case on IE7.
|
|
*
|
|
* @param elem
|
|
* An element to get the attributes for.
|
|
* @return
|
|
* An array containing [name, value] tuples for each attribute.
|
|
* Attribute values will always be strings, but possibly empty strings.
|
|
*/
|
|
function attrs(elem) {
|
|
var as = [];
|
|
var names = attrNames(elem);
|
|
var i;
|
|
var len;
|
|
for (i = 0, len = names.length; i < len; i++) {
|
|
var name = names[i];
|
|
var value = $.attr(elem, name);
|
|
if (null == value) {
|
|
value = "";
|
|
} else {
|
|
value = value.toString();
|
|
}
|
|
as.push([name, value]);
|
|
}
|
|
return as;
|
|
}
|
|
|
|
/**
|
|
* Like indexByClass() but operates on a list of elements instead.
|
|
* The given list may be a NodeList, HTMLCollection, or an array.
|
|
*/
|
|
function indexByClassHaveList(elems, classMap) {
|
|
var index = {},
|
|
indexed,
|
|
classes,
|
|
elem,
|
|
cls,
|
|
len,
|
|
i,
|
|
j;
|
|
for (i = 0, len = elems.length; i < len; i++) {
|
|
elem = elems[i];
|
|
if (elem.className) {
|
|
classes = Strings.words(elem.className);
|
|
for (j = 0; j < classes.length; j++) {
|
|
cls = classes[j];
|
|
if (classMap[cls]) {
|
|
indexed = index[cls];
|
|
if (indexed) {
|
|
indexed.push(elem);
|
|
} else {
|
|
index[cls] = [elem];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return index;
|
|
}
|
|
|
|
/**
|
|
* Indexes descendant elements based on the individual classes in
|
|
* the class attribute.
|
|
*
|
|
* Based on these observations;
|
|
*
|
|
* * $('.class1, .class2') takes twice as long as $('.class1') on IE7.
|
|
*
|
|
* * $('.class1, .class2') is fast on IE8 (approx the same as
|
|
* $('.class'), no matter how many classes), but if the individual
|
|
* elements in the result set should be handled differently, the
|
|
* subsequent hasClass('.class1') and hasClass('.class2') calls
|
|
* slow things down again.
|
|
*
|
|
* * DOM traversal with elem.firstChild elem.nextSibling is very
|
|
* slow on IE7 compared to just iterating over
|
|
* root.getElementsByTagName('*').
|
|
*
|
|
* * $('name.class') is much faster than just $('.class'), but as
|
|
* soon as you need a single class in classMap that may be present
|
|
* on any element, that optimization doesn't gain anything since
|
|
* then you have to examine every element.
|
|
*
|
|
* This function will always take approx. the same amount of time
|
|
* (on IE7 approx. equivalent to a single call to $('.class')) no
|
|
* matter how many entries there are in classMap to index.
|
|
*
|
|
* This function only makes sense for multiple entries in
|
|
* classMap. For a single class lookup, $('.class') or
|
|
* $('name.class') is fine (even better in the latter case).
|
|
*
|
|
* @param root
|
|
* The root element to search for elements to index
|
|
* (will not be included in search).
|
|
* @param classMap
|
|
* A map from class name to boolean true.
|
|
* @return
|
|
* A map from class name to an array of elements with that class.
|
|
* Every entry in classMap for which elements have been found
|
|
* will have a corresponding entry in the returned
|
|
* map. Entries for which no elements have been found, may or
|
|
* may not have an entry in the returned map.
|
|
*/
|
|
function indexByClass(root, classMap) {
|
|
var elems;
|
|
if (Browser.ie7) {
|
|
elems = root.getElementsByTagName('*');
|
|
} else {
|
|
// Optimize for browsers that support querySelectorAll/getElementsByClassName.
|
|
// On IE8 for example, if there is a relatively high
|
|
// elems/resultSet ratio, performance can improve by a factor of 2.
|
|
elems = $(root).find('.' + Maps.keys(classMap).join(',.'));
|
|
}
|
|
return indexByClassHaveList(elems, classMap);
|
|
}
|
|
|
|
/**
|
|
* Indexes descendant elements based on elem.nodeName.
|
|
*
|
|
* Based on these observations:
|
|
*
|
|
* * On IE8, for moderate values of names.length, individual calls to
|
|
* getElementsByTagName is just as fast as $root.find('name, name,
|
|
* name, name').
|
|
*
|
|
* * On IE7, $root.find('name, name, name, name') is extemely slow
|
|
* (can be an order of magnitude slower than individual calls to
|
|
* getElementsByTagName, why is that?).
|
|
*
|
|
* * Although getElementsByTagName is very fast even on IE7, when
|
|
* names.length > 7 an alternative implementation that iterates
|
|
* over all tags and checks names from a hashmap (similar to how
|
|
* indexByClass does it) may become interesting, but
|
|
* names.length > 7 is unlikely.
|
|
*
|
|
* This function only makes sense if the given names array has many
|
|
* entries. For only one or two different names, calling $('name')
|
|
* or context.getElementsByTagName(name) directly is fine (but
|
|
* beware of $('name, name, ...') as explained above).
|
|
*
|
|
* The signature of this function differs from indexByClass by not
|
|
* taking a map but instead an array of names.
|
|
*
|
|
* @param root
|
|
* The root element to search for elements to index
|
|
* (will not be included in search).
|
|
* @param names
|
|
* An array of element names to look for.
|
|
* Names must be in all-uppercase (the same as elem.nodeName).
|
|
* @return
|
|
* A map from element name to an array of elements with that name.
|
|
* Names will be all-uppercase.
|
|
* Arrays will be proper arrays, not NodeLists.
|
|
* Every entry in classMap for which elements have been found
|
|
* will have a corresponding entry in the returned
|
|
* map. Entries for which no elements have been found, may or
|
|
* may not have an entry in the returned map.
|
|
*/
|
|
function indexByName(root, names) {
|
|
var i,
|
|
index = {},
|
|
len;
|
|
for (i = 0, len = names.length; i < len; i++) {
|
|
var name = names[i];
|
|
index[name] = $.makeArray(root.getElementsByTagName(name));
|
|
}
|
|
return index;
|
|
}
|
|
|
|
return {
|
|
moveNextAll: moveNextAll,
|
|
attrNames: attrNames,
|
|
attrs: attrs,
|
|
indexByClass: indexByClass,
|
|
indexByName: indexByName,
|
|
indexByClassHaveList: indexByClassHaveList,
|
|
outerHtml: outerHtml
|
|
};
|
|
});
|