mirror of
https://github.com/UnickSoft/graphonline.git
synced 2026-10-25 13:30:16 +00:00
first commit
This commit is contained in:
commit
c715e2a604
5325 files changed
+329700
No files matched your search
Executable
+15
@@ -0,0 +1,15 @@
|
||||
Copyright (c) The New York Times, CMS Group, Matthew DeLambo
|
||||
Modifications Copyright (c) Loopindex.com, (David *)Frenkiel
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program 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 as the file license.txt. If not, see
|
||||
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
ice includes and was inspired by the following software:
|
||||
--------------------------------------------------------
|
||||
|
||||
Rangy
|
||||
-----
|
||||
|
||||
The MIT License
|
||||
Copyright (c) 2010 Tim Down
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
Viper
|
||||
-----
|
||||
|
||||
Squiz Pty Ltd <products@squiz.net>
|
||||
2010 Squiz Pty Ltd (ACN 084 670 600)
|
||||
|
||||
Viper is a WYSIWYG that does not require the use of editable regions. Instead
|
||||
it utilises the browser's range API to edit the content directly in the browser.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License, version 2, as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program 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 as the file license.txt. If not, see
|
||||
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
|
||||
|
||||
Executable
+128
@@ -0,0 +1,128 @@
|
||||
# ice.js
|
||||
|
||||
Ice is a track changes implementation, built in javascript, for anything that is `contenteditable` on the web. Conceived by the CMS Group at The New York Times, ice has been piloting successfully for articles written in the newsroom.
|
||||
|
||||
## Demo
|
||||
|
||||
[Check it out!](http://NYTimes.github.com/ice/demo/)
|
||||
|
||||
## Download
|
||||
|
||||
[v0.4.2](http://nytimes.github.com/ice/downloads/ice_0.4.2.zip)
|
||||
|
||||
## Features
|
||||
|
||||
- Track multi-user inserts and deletes with the option to turn on and off tracking or highlighting.
|
||||
- A robust API to accept and reject changes, get clean content, and add a lot of configuration.
|
||||
- Plugins for tinymce and wordpress.
|
||||
- Optional plugins to track copy-cut-pasting, convert smart quotes, and create em-dashes.
|
||||
|
||||
## Get Started
|
||||
|
||||
***
|
||||
|
||||
**_Contenteditable initialization_** - If you are comfortable with maintaining your own text editing utilities, then you can initialize ice on any block element:
|
||||
```javascript
|
||||
var tracker = new ice.InlineChangeEditor({
|
||||
// element to track - ice will make it contenteditable
|
||||
element: document.getElementById('mytextelement'),
|
||||
// tell ice to setup/handle events on the `element`
|
||||
handleEvents: true,
|
||||
// set a user object to associate with each change
|
||||
currentUser: { id: 1, name: 'Miss T' }
|
||||
});
|
||||
// setup and start event handling for track changes
|
||||
tracker.startTracking();
|
||||
```
|
||||
Additional options:
|
||||
```javascript
|
||||
var tracker = new ice.InlineChangeEditor({
|
||||
element: document.getElementById('mytextelement'),
|
||||
handleEvents: true,
|
||||
currentUser: { id: 1, name: 'Miss T' },
|
||||
// optional plugins
|
||||
plugins: [
|
||||
// Add title attributes to changes for hover info
|
||||
'IceAddTitlePlugin',
|
||||
// Two successively typed dashes get converted into an em-dash
|
||||
'IceEmdashPlugin',
|
||||
// Track content that is cut and pasted
|
||||
{
|
||||
name: 'IceCopyPastePlugin',
|
||||
settings: {
|
||||
// List of tags and attributes to preserve when cleaning a paste
|
||||
preserve: 'p,a[href],span[id,class]em,strong'
|
||||
}
|
||||
}
|
||||
]
|
||||
}).startTracking();
|
||||
```
|
||||
***
|
||||
|
||||
**_Useful utilities in the API:_**
|
||||
|
||||
**acceptChange, rejectChange**
|
||||
```javascript
|
||||
// Accept/Reject the change at the current range/cursor position or at the given `optionalNode`
|
||||
tracker.acceptChange(optionalNode);
|
||||
tracker.rejectChange(optionalNode);
|
||||
```
|
||||
**acceptAll, rejectAll**
|
||||
```javascript
|
||||
// Accept/Reject all of the changes in the editable region.
|
||||
tracker.acceptAll();
|
||||
tracker.rejectAll();
|
||||
```
|
||||
**getCleanContent**
|
||||
```javascript
|
||||
// Returns a clean version, without tracking tags, of the content in the editable element or
|
||||
// out of the optional `body` param. After cleaning, the `optionalCallback` param is called
|
||||
// which should further modify and return the body.
|
||||
tracker.getCleanContent(optionalBody, optionalCallback);
|
||||
```
|
||||
**setCurrentUser**
|
||||
```javascript
|
||||
// Set the desired user to track. A user object has the following properties: { `id`, `name` }.
|
||||
tracker.setCurrentUser({id: 2, name: 'Miss T'});
|
||||
```
|
||||
**getChanges**
|
||||
```javascript
|
||||
// Get the internal list of change objects which are modeled from all of the change tracking
|
||||
// nodes in the DOM. This might be useful to add a more sophisticated change tracking UI/UX.
|
||||
// The list is key'ed with the unique change ids (`cid attribute`) and points to an object
|
||||
// with metadata for a change: [changeid] => {`type`, `time`, `userid`, `username`}
|
||||
var changes = tracker.getChanges();
|
||||
```
|
||||
***
|
||||
|
||||
**_Tinymce initialization_** - Add the ice plugin to your tinymce plugins directory and include the following in your tinymce init:
|
||||
```javascript
|
||||
tinymce.init({
|
||||
plugins: 'ice',
|
||||
theme_advanced_buttons1: 'ice_togglechanges,ice_toggleshowchanges,iceacceptall,icerejectall,iceaccept,icereject',
|
||||
ice: {
|
||||
user: { name: 'Miss T', id: 1},
|
||||
preserveOnPaste: 'p,a[href],i,em,strong',
|
||||
// Optional param - defaults to the css found in the plugin directory
|
||||
css: 'http://example.com/custom.css'
|
||||
},
|
||||
...
|
||||
});
|
||||
```
|
||||
***
|
||||
|
||||
**_Wordpress initialization_**
|
||||
|
||||
In testing - more to come soon.
|
||||
|
||||
***
|
||||
|
||||
## Limitations/Dependencies
|
||||
|
||||
- ice needs to be initialized after the DOM ready event fires.
|
||||
- ice was originally created for the simple markup behind nytimes.com articles (`p`, `a`, `em`, `strong`). As such, it requires that all text editing takes place in a common root block element, and that there are no other blocks found in the editor. Any type of inline elements are ok, inside of the common root blocks.
|
||||
- Unfortunately, we haven't been able to test this across all browsers and versions. We know that it tests well in modern Firefox (5+) and Webkit browsers, and "seems to work" in IE7+. We intend to do more testing and get a better idea about what ice can support across browsers.
|
||||
|
||||
## License
|
||||
|
||||
[GPL 2.0](https://github.com/NYTimes/ice/blob/master/LICENSE)
|
||||
Executable
+166
@@ -0,0 +1,166 @@
|
||||
(function() {
|
||||
|
||||
var exports = this, Bookmark;
|
||||
|
||||
Bookmark = function(env, range, keepOldBookmarks) {
|
||||
|
||||
this.env = env;
|
||||
this.element = env.element;
|
||||
this.selection = this.env.selection;
|
||||
|
||||
// Remove all bookmarks?
|
||||
if (!keepOldBookmarks) {
|
||||
this.removeBookmarks(this.element);
|
||||
}
|
||||
|
||||
var currRange = range || this.selection.getRangeAt(0);
|
||||
range = currRange.cloneRange();
|
||||
var startContainer = range.startContainer;
|
||||
var endContainer = range.endContainer;
|
||||
var startOffset = range.startOffset;
|
||||
var endOffset = range.endOffset;
|
||||
var tmp;
|
||||
|
||||
// Collapse to the end of range.
|
||||
range.collapse(false);
|
||||
|
||||
var endBookmark = this.env.document.createElement('span');
|
||||
endBookmark.style.display = 'none';
|
||||
ice.dom.setHtml(endBookmark, ' ');
|
||||
ice.dom.addClass(endBookmark, 'iceBookmark iceBookmark_end');
|
||||
endBookmark.setAttribute('iceBookmark', 'end');
|
||||
range.insertNode(endBookmark);
|
||||
if(!ice.dom.isChildOf(endBookmark, this.element)) {
|
||||
this.element.appendChild(endBookmark);
|
||||
}
|
||||
|
||||
// Move the range to where it was before.
|
||||
range.setStart(startContainer, startOffset);
|
||||
range.collapse(true);
|
||||
|
||||
// Create the start bookmark.
|
||||
var startBookmark = this.env.document.createElement('span');
|
||||
startBookmark.style.display = 'none';
|
||||
ice.dom.addClass(startBookmark, 'iceBookmark iceBookmark_start');
|
||||
ice.dom.setHtml(startBookmark, ' ');
|
||||
startBookmark.setAttribute('iceBookmark', 'start');
|
||||
try {
|
||||
range.insertNode(startBookmark);
|
||||
|
||||
// Make sure start and end are in correct position.
|
||||
if (startBookmark.previousSibling === endBookmark) {
|
||||
// Reverse..
|
||||
tmp = startBookmark;
|
||||
startBookmark = endBookmark;
|
||||
endBookmark = tmp;
|
||||
}
|
||||
} catch (e) {
|
||||
// NS_ERROR_UNEXPECTED: I believe this is a Firefox bug.
|
||||
// It seems like if the range is collapsed and the text node is empty
|
||||
// (i.e. length = 0) then Firefox tries to split the node for no reason and fails...
|
||||
ice.dom.insertBefore(endBookmark, startBookmark);
|
||||
}
|
||||
|
||||
if (ice.dom.isChildOf(startBookmark, this.element) === false) {
|
||||
if (this.element.firstChild) {
|
||||
ice.dom.insertBefore(this.element.firstChild, startBookmark);
|
||||
} else {
|
||||
// Should not happen...
|
||||
this.element.appendChild(startBookmark);
|
||||
}
|
||||
}
|
||||
|
||||
if (!endBookmark.previousSibling) {
|
||||
tmp = this.env.document.createTextNode('');
|
||||
ice.dom.insertBefore(endBookmark, tmp);
|
||||
}
|
||||
|
||||
// The original range object must be changed.
|
||||
if (!startBookmark.nextSibling) {
|
||||
tmp = this.env.document.createTextNode('');
|
||||
ice.dom.insertAfter(startBookmark, tmp);
|
||||
}
|
||||
|
||||
currRange.setStart(startBookmark.nextSibling, 0);
|
||||
currRange.setEnd(endBookmark.previousSibling, (endBookmark.previousSibling.length || 0));
|
||||
|
||||
this.start = startBookmark;
|
||||
this.end = endBookmark;
|
||||
};
|
||||
|
||||
Bookmark.prototype = {
|
||||
|
||||
selectBookmark: function() {
|
||||
var range = this.selection.getRangeAt(0);
|
||||
var startPos = null;
|
||||
var endPos = null;
|
||||
var startOffset = 0;
|
||||
var endOffset = null;
|
||||
if (this.start.nextSibling === this.end || ice.dom.getElementsBetween(this.start, this.end).length === 0) {
|
||||
// Bookmark is collapsed.
|
||||
if (this.end.nextSibling) {
|
||||
startPos = ice.dom.getFirstChild(this.end.nextSibling);
|
||||
} else if (this.start.previousSibling) {
|
||||
startPos = ice.dom.getFirstChild(this.start.previousSibling);
|
||||
if (startPos.nodeType === ice.dom.TEXT_NODE) {
|
||||
startOffset = startPos.length;
|
||||
}
|
||||
} else {
|
||||
// Create a text node in parent.
|
||||
this.end.parentNode.appendChild(this.env.document.createTextNode(''));
|
||||
startPos = ice.dom.getFirstChild(this.end.nextSibling);
|
||||
}
|
||||
} else {
|
||||
if (this.start.nextSibling) {
|
||||
startPos = ice.dom.getFirstChild(this.start.nextSibling);
|
||||
} else {
|
||||
if (!this.start.previousSibling) {
|
||||
var tmp = this.env.document.createTextNode('');
|
||||
ice.dom.insertBefore(this.start, tmp);
|
||||
}
|
||||
|
||||
startPos = ice.dom.getLastChild(this.start.previousSibling);
|
||||
startOffset = startPos.length;
|
||||
}
|
||||
|
||||
if (this.end.previousSibling) {
|
||||
endPos = ice.dom.getLastChild(this.end.previousSibling);
|
||||
} else {
|
||||
endPos = ice.dom.getFirstChild(this.end.nextSibling || this.end);
|
||||
endOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ice.dom.remove([this.start, this.end]);
|
||||
|
||||
if (endPos === null) {
|
||||
range.setEnd(startPos, startOffset);
|
||||
range.collapse(false);
|
||||
} else {
|
||||
range.setStart(startPos, startOffset);
|
||||
if (endOffset === null) {
|
||||
endOffset = (endPos.length || 0);
|
||||
}
|
||||
range.setEnd(endPos, endOffset);
|
||||
}
|
||||
|
||||
try {
|
||||
this.selection.addRange(range);
|
||||
} catch (e) {
|
||||
// IE may throw exception for hidden elements..
|
||||
}
|
||||
},
|
||||
|
||||
getBookmark: function(parent, type) {
|
||||
var elem = ice.dom.getClass('iceBookmark_' + type, parent)[0];
|
||||
return elem;
|
||||
},
|
||||
|
||||
removeBookmarks: function(elem) {
|
||||
ice.dom.remove(ice.dom.getClass('iceBookmark', elem, 'span'));
|
||||
}
|
||||
};
|
||||
|
||||
exports.Bookmark = Bookmark;
|
||||
|
||||
}).call(this.ice);
|
||||
Executable
+1035
File diff suppressed because it is too large.
Load diff
Executable
+1924
File diff suppressed because it is too large.
Load diff
+6
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Load the ice dev files
|
||||
*/
|
||||
(function() {
|
||||
// Taken care of in the ice_on_mce.html page...
|
||||
})();
|
||||
Executable
+6848
File diff suppressed because it is too large.
Load diff
Executable
+39
@@ -0,0 +1,39 @@
|
||||
(function() {
|
||||
|
||||
var exports = this;
|
||||
|
||||
var IcePlugin = function(ice_instance) {
|
||||
this._ice = ice_instance;
|
||||
};
|
||||
|
||||
IcePlugin.prototype = {
|
||||
|
||||
start: function() {},
|
||||
clicked: function(e) {
|
||||
return true;
|
||||
},
|
||||
mouseDown: function(e) {
|
||||
return true;
|
||||
},
|
||||
keyDown: function(e) {
|
||||
return true;
|
||||
},
|
||||
keyPress: function(e) {
|
||||
return true;
|
||||
},
|
||||
selectionChanged: function(range) {},
|
||||
setEnabled: function(enabled) {},
|
||||
setDisabled: function(enabled) {},
|
||||
caretUpdated: function() {},
|
||||
nodeInserted: function(node, range) {},
|
||||
nodeCreated: function(node, options) {},
|
||||
caretPositioned: function() {},
|
||||
remove: function() {
|
||||
this._ice.removeKeyPressListener(this);
|
||||
},
|
||||
setSettings: function(settings) {}
|
||||
};
|
||||
|
||||
exports.IcePlugin = IcePlugin;
|
||||
|
||||
}).call(this.ice);
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
(function() {
|
||||
|
||||
var exports = this;
|
||||
|
||||
var IcePluginManager = function(ice_instance) {
|
||||
|
||||
this.plugins = {},
|
||||
this.pluginConstructors = {},
|
||||
this.keyPressListeners = {},
|
||||
this.activePlugin = null,
|
||||
this.pluginSets = {},
|
||||
this.activePluginSet = null,
|
||||
|
||||
this._ice = ice_instance;
|
||||
};
|
||||
|
||||
IcePluginManager.prototype = {
|
||||
|
||||
getPluginNames: function() {
|
||||
var plugins = [];
|
||||
for (var name in this.plugins) {
|
||||
plugins.push(name);
|
||||
}
|
||||
return plugins;
|
||||
},
|
||||
|
||||
addPluginObject: function(pluginName, pluginObj) {
|
||||
this.plugins[pluginName] = pluginObj;
|
||||
},
|
||||
|
||||
addPlugin: function(name, pluginConstructor) {
|
||||
if (typeof pluginConstructor !== 'function') {
|
||||
throw Error('IcePluginException: plugin must be a constructor function');
|
||||
}
|
||||
|
||||
if (ice.dom.isset(this.pluginConstructors[name]) === false) {
|
||||
this.pluginConstructors[name] = pluginConstructor;
|
||||
}
|
||||
},
|
||||
|
||||
loadPlugins: function(plugins, callback) {
|
||||
if (plugins.length === 0) {
|
||||
callback.call(this);
|
||||
} else {
|
||||
var plugin = plugins.shift();
|
||||
if (typeof plugin === 'object') {
|
||||
plugin = plugin.name;
|
||||
}
|
||||
|
||||
if (ice.dom.isset(ice._plugin[plugin]) === true) {
|
||||
this.addPlugin(plugin, ice._plugin[plugin]);
|
||||
this.loadPlugins(plugins, callback);
|
||||
} else {
|
||||
throw new Error('plugin was not included in the page: ' + plugin);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_enableSet: function(name) {
|
||||
this.activePluginSet = name;
|
||||
var pSetLen = this.pluginSets[name].length;
|
||||
for (var i = 0; i < pSetLen; i++) {
|
||||
var plugin = this.pluginSets[name][i];
|
||||
var pluginName = '';
|
||||
if (typeof plugin === 'object') {
|
||||
pluginName = plugin.name;
|
||||
} else {
|
||||
pluginName = plugin;
|
||||
}
|
||||
|
||||
var pluginConstructor = this.pluginConstructors[pluginName];
|
||||
if (pluginConstructor) {
|
||||
var pluginObj = new pluginConstructor(this._ice);
|
||||
this.plugins[pluginName] = pluginObj;
|
||||
|
||||
if (ice.dom.isset(plugin.settings) === true) {
|
||||
pluginObj.setSettings(plugin.settings);
|
||||
}
|
||||
|
||||
pluginObj.start();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setActivePlugin: function(name) {
|
||||
this.activePlugin = name;
|
||||
},
|
||||
|
||||
getActivePlugin: function() {
|
||||
return this.activePlugin;
|
||||
},
|
||||
|
||||
_getPluginName: function(pluginConstructor) {
|
||||
var fn = pluginConstructor.toString();
|
||||
var start = 'function '.length;
|
||||
var name = fn.substr(start, (fn.indexOf('(') - start));
|
||||
return name;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes specified plugin.
|
||||
*/
|
||||
removePlugin: function(plugin) {
|
||||
if (this.plugins[plugin]) {
|
||||
// Call the remove fn of the plugin incase it needs to do cleanup.
|
||||
this.plugins[plugin].remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the plugin object for specified plugin name.
|
||||
*/
|
||||
getPlugin: function(name) {
|
||||
return this.plugins[name];
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new set of plugins.
|
||||
*/
|
||||
usePlugins: function(name, plugins, callback) {
|
||||
var self = this;
|
||||
if (ice.dom.isset(plugins) === true) {
|
||||
this.pluginSets[name] = plugins;
|
||||
} else {
|
||||
this.pluginSets[name] = [];
|
||||
}
|
||||
var clone = this.pluginSets[name].concat([]);
|
||||
this.loadPlugins(clone, function() {
|
||||
self._enableSet(name);
|
||||
if(callback) callback.call(this);
|
||||
});
|
||||
},
|
||||
|
||||
disablePlugin: function(name) {
|
||||
this.plugins[name].disable();
|
||||
},
|
||||
|
||||
isPluginElement: function(element) {
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].isPluginElement) {
|
||||
if (this.plugins[i].isPluginElement(element) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
fireKeyPressed: function(e) {
|
||||
if (this._fireKeyPressFns(e, 'all_keys') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var eKeys = [];
|
||||
if (e.ctrlKey === true || e.metaKey === true) {
|
||||
eKeys.push('ctrl');
|
||||
}
|
||||
|
||||
if (e.shiftKey === true) {
|
||||
eKeys.push('shift');
|
||||
}
|
||||
|
||||
if (e.altKey === true) {
|
||||
eKeys.push('alt');
|
||||
}
|
||||
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
eKeys.push('enter');
|
||||
break;
|
||||
|
||||
case ice.dom.DOM_VK_LEFT:
|
||||
eKeys.push('left');
|
||||
break;
|
||||
|
||||
case ice.dom.DOM_VK_RIGHT:
|
||||
eKeys.push('right');
|
||||
break;
|
||||
|
||||
case ice.dom.DOM_VK_UP:
|
||||
eKeys.push('up');
|
||||
break;
|
||||
|
||||
case ice.dom.DOM_VK_DOWN:
|
||||
eKeys.push('down');
|
||||
break;
|
||||
|
||||
case 9:
|
||||
eKeys.push('tab');
|
||||
break;
|
||||
|
||||
case ice.dom.DOM_VK_DELETE:
|
||||
eKeys.push('delete');
|
||||
break;
|
||||
|
||||
default:
|
||||
var code;
|
||||
if (e.keyCode) {
|
||||
code = e.keyCode;
|
||||
} else if (e.which) {
|
||||
code = e.which;
|
||||
}
|
||||
|
||||
// Other characters (a-z0-9..).
|
||||
if (code) {
|
||||
eKeys.push(String.fromCharCode(code).toLowerCase());
|
||||
}
|
||||
break;
|
||||
}//end switch
|
||||
|
||||
var eKeysStr = eKeys.sort().join('+');
|
||||
|
||||
return this._fireKeyPressFns(e, eKeysStr);
|
||||
|
||||
},
|
||||
|
||||
_fireKeyPressFns: function(e, eKeysStr) {
|
||||
if (this.keyPressListeners[eKeysStr]) {
|
||||
var ln = this.keyPressListeners[eKeysStr].length;
|
||||
for (var i = 0; i < ln; i++) {
|
||||
var listener = this.keyPressListeners[eKeysStr][i];
|
||||
var eventFn = listener.fn;
|
||||
var plugin = listener.plugin;
|
||||
var data = listener.data;
|
||||
|
||||
if (eventFn) {
|
||||
if (ice.dom.isFn(eventFn) === true) {
|
||||
if (eventFn.call(plugin, e, data) === true) {
|
||||
ice.dom.preventDefault(e);
|
||||
return false;
|
||||
}
|
||||
} else if (plugin[eventFn] && plugin[eventFn].call(plugin, e, data) === true) {
|
||||
ice.dom.preventDefault(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
fireSelectionChanged: function(range) {
|
||||
for (var i in this.plugins) {
|
||||
this.plugins[i].selectionChanged(range);
|
||||
}
|
||||
},
|
||||
|
||||
fireNodeInserted: function(node, range) {
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].nodeInserted(node, range) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fireNodeCreated: function(node, option) {
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].nodeCreated(node, option) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fireCaretPositioned: function() {
|
||||
for (var i in this.plugins) {
|
||||
this.plugins[i].caretPositioned()
|
||||
}
|
||||
},
|
||||
|
||||
fireClicked: function(e) {
|
||||
var val = true;
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].clicked(e) === false) {
|
||||
val = false;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
fireMouseDown: function(e) {
|
||||
var val = true;
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].mouseDown(e) === false) {
|
||||
val = false;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
fireKeyDown: function(e) {
|
||||
var val = true;
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].keyDown(e) === false) {
|
||||
val = false;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
fireKeyPress: function(e) {
|
||||
var val = true;
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].keyPress(e) === false) {
|
||||
val = false;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
fireEnabled: function(enabled) {
|
||||
for (var i in this.plugins) {
|
||||
this.plugins[i].setEnabled(enabled);
|
||||
}
|
||||
},
|
||||
|
||||
fireDisabled: function(disabled) {
|
||||
for (var i in this.plugins) {
|
||||
this.plugins[i].setDisabled(disabled);
|
||||
}
|
||||
},
|
||||
|
||||
fireCaretUpdated: function() {
|
||||
for (var i in this.plugins) {
|
||||
if (this.plugins[i].caretUpdated) {
|
||||
this.plugins[i].caretUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports._plugin = {};
|
||||
exports.IcePluginManager = IcePluginManager;
|
||||
|
||||
}).call(this.ice);
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
|
||||
//@ sourceMappingURL=jquery.min.map
|
||||
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
|
||||
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
|
||||
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
|
||||
+498
@@ -0,0 +1,498 @@
|
||||
/*!
|
||||
* jQuery Migrate - v1.0.0 - 2013-01-14
|
||||
* https://github.com/jquery/jquery-migrate
|
||||
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
|
||||
*/
|
||||
(function( jQuery, window, undefined ) {
|
||||
"use strict";
|
||||
|
||||
|
||||
var warnedAbout = {};
|
||||
|
||||
// List of warnings already given; public read only
|
||||
jQuery.migrateWarnings = [];
|
||||
|
||||
// Set to true to prevent console output; migrateWarnings still maintained
|
||||
// jQuery.migrateMute = false;
|
||||
|
||||
// Forget any warnings we've already given; public
|
||||
jQuery.migrateReset = function() {
|
||||
warnedAbout = {};
|
||||
jQuery.migrateWarnings.length = 0;
|
||||
};
|
||||
|
||||
function migrateWarn( msg) {
|
||||
if ( !warnedAbout[ msg ] ) {
|
||||
warnedAbout[ msg ] = true;
|
||||
jQuery.migrateWarnings.push( msg );
|
||||
if ( window.console && console.warn && !jQuery.migrateMute ) {
|
||||
console.warn( "JQMIGRATE: " + msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function migrateWarnProp( obj, prop, value, msg ) {
|
||||
if ( Object.defineProperty ) {
|
||||
// On ES5 browsers (non-oldIE), warn if the code tries to get prop;
|
||||
// allow property to be overwritten in case some other plugin wants it
|
||||
try {
|
||||
Object.defineProperty( obj, prop, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
migrateWarn( msg );
|
||||
return value;
|
||||
},
|
||||
set: function( newValue ) {
|
||||
migrateWarn( msg );
|
||||
value = newValue;
|
||||
}
|
||||
});
|
||||
return;
|
||||
} catch( err ) {
|
||||
// IE8 is a dope about Object.defineProperty, can't warn there
|
||||
}
|
||||
}
|
||||
|
||||
// Non-ES5 (or broken) browser; just set the property
|
||||
jQuery._definePropertyBroken = true;
|
||||
obj[ prop ] = value;
|
||||
}
|
||||
|
||||
if ( document.compatMode === "BackCompat" ) {
|
||||
// jQuery has never supported or tested Quirks Mode
|
||||
migrateWarn( "jQuery is not compatible with Quirks Mode" );
|
||||
}
|
||||
|
||||
|
||||
var attrFn = {},
|
||||
attr = jQuery.attr,
|
||||
valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
|
||||
function() { return null; },
|
||||
valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
|
||||
function() { return undefined; },
|
||||
rnoType = /^(?:input|button)$/i,
|
||||
rnoAttrNodeType = /^[238]$/,
|
||||
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
|
||||
ruseDefault = /^(?:checked|selected)$/i;
|
||||
|
||||
// jQuery.attrFn
|
||||
migrateWarnProp( jQuery, "attrFn", attrFn, "jQuery.attrFn is deprecated" );
|
||||
|
||||
jQuery.attr = function( elem, name, value, pass ) {
|
||||
var lowerName = name.toLowerCase(),
|
||||
nType = elem && elem.nodeType;
|
||||
|
||||
if ( pass ) {
|
||||
migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
|
||||
if ( elem && !rnoAttrNodeType.test( nType ) && jQuery.isFunction( jQuery.fn[ name ] ) ) {
|
||||
return jQuery( elem )[ name ]( value );
|
||||
}
|
||||
}
|
||||
|
||||
// Warn if user tries to set `type` since it breaks on IE 6/7/8
|
||||
if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) ) {
|
||||
migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
|
||||
}
|
||||
|
||||
// Restore boolHook for boolean property/attribute synchronization
|
||||
if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
|
||||
jQuery.attrHooks[ lowerName ] = {
|
||||
get: function( elem, name ) {
|
||||
// Align boolean attributes with corresponding properties
|
||||
// Fall back to attribute presence where some booleans are not supported
|
||||
var attrNode,
|
||||
property = jQuery.prop( elem, name );
|
||||
return property === true || typeof property !== "boolean" &&
|
||||
( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
|
||||
|
||||
name.toLowerCase() :
|
||||
undefined;
|
||||
},
|
||||
set: function( elem, value, name ) {
|
||||
var propName;
|
||||
if ( value === false ) {
|
||||
// Remove boolean attributes when set to false
|
||||
jQuery.removeAttr( elem, name );
|
||||
} else {
|
||||
// value is true since we know at this point it's type boolean and not false
|
||||
// Set boolean attributes to the same name and set the DOM property
|
||||
propName = jQuery.propFix[ name ] || name;
|
||||
if ( propName in elem ) {
|
||||
// Only set the IDL specifically if it already exists on the element
|
||||
elem[ propName ] = true;
|
||||
}
|
||||
|
||||
elem.setAttribute( name, name.toLowerCase() );
|
||||
}
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
// Warn only for attributes that can remain distinct from their properties post-1.9
|
||||
if ( ruseDefault.test( lowerName ) ) {
|
||||
migrateWarn( "jQuery.fn.attr(" + lowerName + ") may use property instead of attribute" );
|
||||
}
|
||||
}
|
||||
|
||||
return attr.call( jQuery, elem, name, value );
|
||||
};
|
||||
|
||||
// attrHooks: value
|
||||
jQuery.attrHooks.value = {
|
||||
get: function( elem, name ) {
|
||||
var nodeName = ( elem.nodeName || "" ).toLowerCase();
|
||||
if ( nodeName === "button" ) {
|
||||
return valueAttrGet.apply( this, arguments );
|
||||
}
|
||||
if ( nodeName !== "input" && nodeName !== "option" ) {
|
||||
migrateWarn("property-based jQuery.fn.attr('value') is deprecated");
|
||||
}
|
||||
return name in elem ?
|
||||
elem.value :
|
||||
null;
|
||||
},
|
||||
set: function( elem, value ) {
|
||||
var nodeName = ( elem.nodeName || "" ).toLowerCase();
|
||||
if ( nodeName === "button" ) {
|
||||
return valueAttrSet.apply( this, arguments );
|
||||
}
|
||||
if ( nodeName !== "input" && nodeName !== "option" ) {
|
||||
migrateWarn("property-based jQuery.fn.attr('value', val) is deprecated");
|
||||
}
|
||||
// Does not return so that setAttribute is also used
|
||||
elem.value = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var matched, browser,
|
||||
oldInit = jQuery.fn.init,
|
||||
// Note this does NOT include the # XSS fix from 1.7!
|
||||
rquickExpr = /^(?:.*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;
|
||||
|
||||
// $(html) "looks like html" rule change
|
||||
jQuery.fn.init = function( selector, context, rootjQuery ) {
|
||||
var match;
|
||||
|
||||
if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
|
||||
(match = rquickExpr.exec( selector )) && match[1] ) {
|
||||
// This is an HTML string according to the "old" rules; is it still?
|
||||
if ( selector.charAt( 0 ) !== "<" ) {
|
||||
migrateWarn("$(html) HTML strings must start with '<' character");
|
||||
}
|
||||
// Now process using loose rules; let pre-1.8 play too
|
||||
if ( context && context.context ) {
|
||||
// jQuery object as context; parseHTML expects a DOM object
|
||||
context = context.context;
|
||||
}
|
||||
if ( jQuery.parseHTML ) {
|
||||
return oldInit.call( this, jQuery.parseHTML( jQuery.trim(selector), context, true ),
|
||||
context, rootjQuery );
|
||||
}
|
||||
}
|
||||
return oldInit.apply( this, arguments );
|
||||
};
|
||||
jQuery.fn.init.prototype = jQuery.fn;
|
||||
|
||||
jQuery.uaMatch = function( ua ) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(msie) ([\w.]+)/.exec( ua ) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
||||
[];
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || "",
|
||||
version: match[ 2 ] || "0"
|
||||
};
|
||||
};
|
||||
|
||||
matched = jQuery.uaMatch( navigator.userAgent );
|
||||
browser = {};
|
||||
|
||||
if ( matched.browser ) {
|
||||
browser[ matched.browser ] = true;
|
||||
browser.version = matched.version;
|
||||
}
|
||||
|
||||
// Chrome is Webkit, but Webkit is also Safari.
|
||||
if ( browser.chrome ) {
|
||||
browser.webkit = true;
|
||||
} else if ( browser.webkit ) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
jQuery.browser = browser;
|
||||
|
||||
// Warn if the code tries to get jQuery.browser
|
||||
migrateWarnProp( jQuery, "browser", browser, "jQuery.browser is deprecated" );
|
||||
|
||||
jQuery.sub = function() {
|
||||
function jQuerySub( selector, context ) {
|
||||
return new jQuerySub.fn.init( selector, context );
|
||||
}
|
||||
jQuery.extend( true, jQuerySub, this );
|
||||
jQuerySub.superclass = this;
|
||||
jQuerySub.fn = jQuerySub.prototype = this();
|
||||
jQuerySub.fn.constructor = jQuerySub;
|
||||
jQuerySub.sub = this.sub;
|
||||
jQuerySub.fn.init = function init( selector, context ) {
|
||||
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
|
||||
context = jQuerySub( context );
|
||||
}
|
||||
|
||||
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
|
||||
};
|
||||
jQuerySub.fn.init.prototype = jQuerySub.fn;
|
||||
var rootjQuerySub = jQuerySub(document);
|
||||
migrateWarn( "jQuery.sub() is deprecated" );
|
||||
return jQuerySub;
|
||||
};
|
||||
|
||||
|
||||
var oldFnData = jQuery.fn.data;
|
||||
|
||||
jQuery.fn.data = function( name ) {
|
||||
var ret, evt,
|
||||
elem = this[0];
|
||||
|
||||
// Handles 1.7 which has this behavior and 1.8 which doesn't
|
||||
if ( elem && name === "events" && arguments.length === 1 ) {
|
||||
ret = jQuery.data( elem, name );
|
||||
evt = jQuery._data( elem, name );
|
||||
if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
|
||||
migrateWarn("Use of jQuery.fn.data('events') is deprecated");
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
return oldFnData.apply( this, arguments );
|
||||
};
|
||||
|
||||
|
||||
var rscriptType = /\/(java|ecma)script/i,
|
||||
oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack,
|
||||
oldFragment = jQuery.buildFragment;
|
||||
|
||||
jQuery.fn.andSelf = function() {
|
||||
migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
|
||||
return oldSelf.apply( this, arguments );
|
||||
};
|
||||
|
||||
// Since jQuery.clean is used internally on older versions, we only shim if it's missing
|
||||
if ( !jQuery.clean ) {
|
||||
jQuery.clean = function( elems, context, fragment, scripts ) {
|
||||
// Set context per 1.8 logic
|
||||
context = context || document;
|
||||
context = !context.nodeType && context[0] || context;
|
||||
context = context.ownerDocument || context;
|
||||
|
||||
migrateWarn("jQuery.clean() is deprecated");
|
||||
|
||||
var i, elem, handleScript, jsTags,
|
||||
ret = [];
|
||||
|
||||
jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
|
||||
|
||||
// Complex logic lifted directly from jQuery 1.8
|
||||
if ( fragment ) {
|
||||
// Special handling of each script element
|
||||
handleScript = function( elem ) {
|
||||
// Check if we consider it executable
|
||||
if ( !elem.type || rscriptType.test( elem.type ) ) {
|
||||
// Detach the script and store it in the scripts array (if provided) or the fragment
|
||||
// Return truthy to indicate that it has been handled
|
||||
return scripts ?
|
||||
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
|
||||
fragment.appendChild( elem );
|
||||
}
|
||||
};
|
||||
|
||||
for ( i = 0; (elem = ret[i]) != null; i++ ) {
|
||||
// Check if we're done after handling an executable script
|
||||
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
|
||||
// Append to fragment and handle embedded scripts
|
||||
fragment.appendChild( elem );
|
||||
if ( typeof elem.getElementsByTagName !== "undefined" ) {
|
||||
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
|
||||
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
|
||||
|
||||
// Splice the scripts into ret after their former ancestor and advance our index beyond them
|
||||
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
|
||||
i += jsTags.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
|
||||
jQuery.buildFragment = function( elems, context, scripts, selection ) {
|
||||
var ret,
|
||||
warning = "jQuery.buildFragment() is deprecated";
|
||||
|
||||
// Set context per 1.8 logic
|
||||
context = context || document;
|
||||
context = !context.nodeType && context[0] || context;
|
||||
context = context.ownerDocument || context;
|
||||
|
||||
try {
|
||||
ret = oldFragment.call( jQuery, elems, context, scripts, selection );
|
||||
|
||||
// jQuery < 1.8 required arrayish context; jQuery 1.9 fails on it
|
||||
} catch( x ) {
|
||||
ret = oldFragment.call( jQuery, elems, context.nodeType ? [ context ] : context[ 0 ], scripts, selection );
|
||||
|
||||
// Success from tweaking context means buildFragment was called by the user
|
||||
migrateWarn( warning );
|
||||
}
|
||||
|
||||
// jQuery < 1.9 returned an object instead of the fragment itself
|
||||
if ( !ret.fragment ) {
|
||||
migrateWarnProp( ret, "fragment", ret, warning );
|
||||
migrateWarnProp( ret, "cacheable", false, warning );
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
var eventAdd = jQuery.event.add,
|
||||
eventRemove = jQuery.event.remove,
|
||||
eventTrigger = jQuery.event.trigger,
|
||||
oldToggle = jQuery.fn.toggle,
|
||||
oldLive = jQuery.fn.live,
|
||||
oldDie = jQuery.fn.die,
|
||||
ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
|
||||
rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
|
||||
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
|
||||
hoverHack = function( events ) {
|
||||
if ( typeof( events ) != "string" || jQuery.event.special.hover ) {
|
||||
return events;
|
||||
}
|
||||
if ( rhoverHack.test( events ) ) {
|
||||
migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
|
||||
}
|
||||
return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
|
||||
};
|
||||
|
||||
// Event props removed in 1.9, put them back if needed; no practical way to warn them
|
||||
if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
|
||||
jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
|
||||
}
|
||||
|
||||
// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
|
||||
migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
|
||||
|
||||
// Support for 'hover' pseudo-event and ajax event warnings
|
||||
jQuery.event.add = function( elem, types, handler, data, selector ){
|
||||
if ( elem !== document && rajaxEvent.test( types ) ) {
|
||||
migrateWarn( "AJAX events should be attached to document: " + types );
|
||||
}
|
||||
eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
|
||||
};
|
||||
jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
|
||||
eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
|
||||
};
|
||||
|
||||
jQuery.fn.error = function() {
|
||||
var args = Array.prototype.slice.call( arguments, 0);
|
||||
migrateWarn("jQuery.fn.error() is deprecated");
|
||||
args.splice( 0, 0, "error" );
|
||||
if ( arguments.length ) {
|
||||
return this.bind.apply( this, args );
|
||||
}
|
||||
// error event should not bubble to window, although it does pre-1.7
|
||||
this.triggerHandler.apply( this, args );
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.toggle = function( fn, fn2 ) {
|
||||
|
||||
// Don't mess with animation or css toggles
|
||||
if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
|
||||
return oldToggle.apply( this, arguments );
|
||||
}
|
||||
migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
|
||||
|
||||
// Save reference to arguments for access in closure
|
||||
var args = arguments,
|
||||
guid = fn.guid || jQuery.guid++,
|
||||
i = 0,
|
||||
toggler = function( event ) {
|
||||
// Figure out which function to execute
|
||||
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
|
||||
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
|
||||
|
||||
// Make sure that clicks stop
|
||||
event.preventDefault();
|
||||
|
||||
// and execute the function
|
||||
return args[ lastToggle ].apply( this, arguments ) || false;
|
||||
};
|
||||
|
||||
// link all the functions, so any of them can unbind this click handler
|
||||
toggler.guid = guid;
|
||||
while ( i < args.length ) {
|
||||
args[ i++ ].guid = guid;
|
||||
}
|
||||
|
||||
return this.click( toggler );
|
||||
};
|
||||
|
||||
jQuery.fn.live = function( types, data, fn ) {
|
||||
migrateWarn("jQuery.fn.live() is deprecated");
|
||||
if ( oldLive ) {
|
||||
return oldLive.apply( this, arguments );
|
||||
}
|
||||
jQuery( this.context ).on( types, this.selector, data, fn );
|
||||
return this;
|
||||
};
|
||||
|
||||
jQuery.fn.die = function( types, fn ) {
|
||||
migrateWarn("jQuery.fn.die() is deprecated");
|
||||
if ( oldDie ) {
|
||||
return oldDie.apply( this, arguments );
|
||||
}
|
||||
jQuery( this.context ).off( types, this.selector || "**", fn );
|
||||
return this;
|
||||
};
|
||||
|
||||
// Turn global events into document-triggered events
|
||||
jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
|
||||
if ( !elem & !rajaxEvent.test( event ) ) {
|
||||
migrateWarn( "Global events are undocumented and deprecated" );
|
||||
}
|
||||
return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
|
||||
};
|
||||
jQuery.each( ajaxEvents.split("|"),
|
||||
function( _, name ) {
|
||||
jQuery.event.special[ name ] = {
|
||||
setup: function() {
|
||||
var elem = this;
|
||||
|
||||
// The document needs no shimming; must be !== for oldIE
|
||||
if ( elem !== document ) {
|
||||
jQuery.event.add( document, name + "." + jQuery.guid, function() {
|
||||
jQuery.event.trigger( name, null, elem, true );
|
||||
});
|
||||
jQuery._data( this, name, jQuery.guid++ );
|
||||
}
|
||||
return false;
|
||||
},
|
||||
teardown: function() {
|
||||
if ( this !== document ) {
|
||||
jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
})( jQuery, window );
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
|
||||
//@ sourceMappingURL=jquery.min.map
|
||||
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
|
||||
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
|
||||
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
(function() {
|
||||
|
||||
var exports = this, IceAddTitlePlugin;
|
||||
|
||||
IceAddTitlePlugin = function(ice_instance) {
|
||||
this._ice = ice_instance;
|
||||
};
|
||||
|
||||
IceAddTitlePlugin.prototype = {
|
||||
nodeCreated: function(node, option) {
|
||||
node.setAttribute('title', (option.action || 'Modified') + ' by ' + node.getAttribute(this._ice.userNameAttribute)
|
||||
+ ' - ' + ice.dom.date('m/d/Y h:ia', parseInt(node.getAttribute(this._ice.timeAttribute))));
|
||||
}
|
||||
};
|
||||
|
||||
ice.dom.noInclusionInherits(IceAddTitlePlugin, ice.IcePlugin);
|
||||
exports._plugin.IceAddTitlePlugin = IceAddTitlePlugin;
|
||||
|
||||
}).call(this.ice);
|
||||
+510
@@ -0,0 +1,510 @@
|
||||
(function() {
|
||||
|
||||
var exports = this, IceCopyPastePlugin;
|
||||
|
||||
IceCopyPastePlugin = function(ice_instance) {
|
||||
this._ice = ice_instance;
|
||||
this._tmpNode = null;
|
||||
this._tmpNodeTagName = 'icepaste';
|
||||
this._pasteId = 'icepastediv';
|
||||
var self = this;
|
||||
|
||||
// API
|
||||
|
||||
// 'formatted' - paste will be MS Word cleaned.
|
||||
// 'formattedClean' - paste will be MS Word cleaned, insert and
|
||||
// delete tags will be removed keeping insert content in place,
|
||||
// and tags not found in `preserve` will be stripped.
|
||||
this.pasteType = 'formattedClean';
|
||||
|
||||
// Subset of tags that will not be stripped when pasteType
|
||||
// is set to 'formattedClean'. Parameter is of type string with
|
||||
// comma delimited tag and attribute definitions. For example:
|
||||
// 'p,a[href],i[style|title],span[*]'
|
||||
// Would allow `p`, `a`, `i` and `span` tags. The attributes for
|
||||
// each one of these tags would be cleaned as follows: `p` tags
|
||||
// would have all attributes removed, `a` tags will have all but
|
||||
// `href` attributes removed, `i` tags will have all but `style`
|
||||
// and `title` attributes removed, and `span` tags will keep all attributes.
|
||||
this.preserve = 'p';
|
||||
|
||||
// Callback triggered before any paste cleaning happens
|
||||
this.beforePasteClean = function(body) { return body; };
|
||||
|
||||
// Callback triggered at the end of the paste cleaning
|
||||
this.afterPasteClean = function(body) { return body; };
|
||||
|
||||
// Event Listeners
|
||||
ice_instance.element.oncopy = function() { return self.handleCopy.apply(self); };
|
||||
// ice_instance.element.oncut = function() { return self.handleCut.apply(self); };
|
||||
|
||||
// We can't listen for `onpaste` unless we use an algorithm that temporarily switches
|
||||
// out the body and lets the browser paste there (found it hard to maintain in mce).
|
||||
// Instead, we'll watch the keydown event and handle paste with a typical temp element
|
||||
// algorithm, which means that pasting from the context menu won't work.
|
||||
};
|
||||
|
||||
IceCopyPastePlugin.prototype = {
|
||||
|
||||
setSettings: function(settings) {
|
||||
settings = settings || {};
|
||||
ice.dom.extend(this, settings);
|
||||
|
||||
this.preserve += ',' + this._tmpNodeTagName;
|
||||
this.setupPreserved();
|
||||
},
|
||||
|
||||
keyDown: function(e) {
|
||||
if (e.metaKey !== true && e.ctrlKey !== true) {
|
||||
return;
|
||||
}
|
||||
if(e.keyCode == 86) {
|
||||
this.handlePaste();
|
||||
}
|
||||
else if(e.keyCode == 88) {
|
||||
this.handleCut();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
keyPress: function(e){
|
||||
var c = null;
|
||||
if (e.which == null) {
|
||||
// IE.
|
||||
c = String.fromCharCode(e.keyCode);
|
||||
} else if (e.which > 0) {
|
||||
c = String.fromCharCode(e.which);
|
||||
}
|
||||
var self = this;
|
||||
if(this.cutElement && c === 'x'){
|
||||
if(ice.dom.isBrowser("webkit")){
|
||||
self.cutElement.focus();
|
||||
}
|
||||
} else if (c === 'v'){
|
||||
if(ice.dom.isBrowser("webkit")){
|
||||
var div = document.getElementById(self._pasteId);
|
||||
div.focus();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
handleCopy: function(e) {},
|
||||
|
||||
// Inserts a temporary placeholder for the current range and removes
|
||||
// the contents of the ice element body and calls a paste handler.
|
||||
handlePaste: function(e) {
|
||||
|
||||
var range = this._ice.getCurrentRange();
|
||||
|
||||
if(!range.collapsed) {
|
||||
if(this._ice.isTracking) {
|
||||
this._ice.deleteContents();
|
||||
range = range.cloneRange();
|
||||
} else {
|
||||
range.deleteContents();
|
||||
range.collapse(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(this._ice.isTracking)
|
||||
this._ice._moveRangeToValidTrackingPos(range);
|
||||
|
||||
if(range.startContainer == this._ice.element) {
|
||||
// Fix a potentially empty body with a bad selection
|
||||
var firstBlock = ice.dom.find(this._ice.element, this._ice.blockEl)[0];
|
||||
if(!firstBlock) {
|
||||
firstBlock = ice.dom.create('<' + this._ice.blockEl + ' ><br/></' + this._ice.blockEl + '>');
|
||||
this._ice.element.appendChild(firstBlock);
|
||||
}
|
||||
range.setStart(firstBlock, 0);
|
||||
range.collapse(true);
|
||||
this._ice.env.selection.addRange(range);
|
||||
}
|
||||
|
||||
|
||||
this._tmpNode = this._ice.env.document.createElement(this._tmpNodeTagName);
|
||||
range.insertNode(this._tmpNode);
|
||||
|
||||
switch (this.pasteType) {
|
||||
case 'formatted':
|
||||
this.setupPaste();
|
||||
break;
|
||||
case 'formattedClean':
|
||||
this.setupPaste(true);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// Create a temporary div and set focus to it so that the browser can paste into it.
|
||||
// Set a timeout to push a paste handler on to the end of the execution stack.
|
||||
setupPaste: function(stripTags) {
|
||||
var div = this.createDiv(this._pasteId), self = this;
|
||||
|
||||
div.onpaste = function() {
|
||||
setTimeout(function(){
|
||||
self.handlePasteValue(stripTags);
|
||||
},0);
|
||||
};
|
||||
|
||||
if(this._ice.env.frame){
|
||||
if(ice.dom.isBrowser("webkit")){
|
||||
div.blur();
|
||||
setTimeout(function(){
|
||||
div.focus();
|
||||
}, 0);
|
||||
} else {
|
||||
div.focus();
|
||||
}
|
||||
}
|
||||
else{
|
||||
div.focus();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// By the time we get here, the pasted content will already be in the body. Extract the
|
||||
// paste, format it, remove any Microsoft or extraneous tags outside of `this.preserve`
|
||||
// and merge the pasted content into the original fragment body.
|
||||
handlePasteValue: function(stripTags) {
|
||||
// Get the pasted content.
|
||||
var html = ice.dom.getHtml(document.getElementById(this._pasteId));
|
||||
var childBlocks = ice.dom.children('<div>' + html + '</div>', this._ice.blockEl);
|
||||
if(childBlocks.length === 1 && ice.dom.getNodeTextContent('<div>' + html + '</div>') === ice.dom.getNodeTextContent(childBlocks)) {
|
||||
html = ice.dom.getHtml(html);
|
||||
}
|
||||
|
||||
html = this.beforePasteClean.call(this, html);
|
||||
|
||||
if(stripTags) {
|
||||
|
||||
// Strip out change tracking tags.
|
||||
html = this._ice.getCleanContent(html);
|
||||
html = this.stripPaste(html);
|
||||
}
|
||||
|
||||
html = this.afterPasteClean.call(this, html);
|
||||
html = ice.dom.trim(html);
|
||||
var range = this._ice.getCurrentRange();
|
||||
range.setStartAfter(this._tmpNode);
|
||||
range.collapse(true);
|
||||
|
||||
var innerBlock = null, lastEl = null, newEl = null;
|
||||
var fragment = range.createContextualFragment(html);
|
||||
var changeid = this._ice.startBatchChange();
|
||||
|
||||
// If fragment contains block level elements, most likely we will need to
|
||||
// do some splitting so we do not have P tags in P tags, etc. Split the
|
||||
// container from current selection and then insert paste contents after it.
|
||||
if(ice.dom.hasBlockChildren(fragment)) {
|
||||
// Split from current selection.
|
||||
var block = ice.dom.isChildOfTagName(this._tmpNode, this._ice.blockEl);
|
||||
range.setEndAfter(block.lastChild);
|
||||
this._ice.selection.addRange(range);
|
||||
var contents = range.extractContents();
|
||||
var newblock = this._ice.env.document.createElement(this._ice.blockEl);
|
||||
newblock.appendChild(contents);
|
||||
ice.dom.insertAfter(block, newblock);
|
||||
|
||||
range.setStart(newblock, 0);
|
||||
range.collapse(true);
|
||||
this._ice.selection.addRange(range);
|
||||
var prevBlock = range.startContainer;
|
||||
|
||||
// Paste all of the children in the fragment.
|
||||
while(fragment.firstChild) {
|
||||
if(fragment.firstChild.nodeType === 3 && !jQuery.trim(fragment.firstChild.nodeValue)) {
|
||||
fragment.removeChild(fragment.firstChild);
|
||||
continue;
|
||||
}
|
||||
// We may have blocks with text nodes at the beginning or end. For example, this paste:
|
||||
// textnode <p>blocktext</p> <p>blocktext</p> moretext
|
||||
// In which case we wrap the leading or trailing text nodes in blocks.
|
||||
if(ice.dom.isBlockElement(fragment.firstChild)) {
|
||||
if(fragment.firstChild.textContent !== "") {
|
||||
innerBlock = null;
|
||||
var insert = null;
|
||||
if(this._ice.isTracking) {
|
||||
insert = this._ice.createIceNode('insertType');
|
||||
this._ice.addChange('insertType', [insert]);
|
||||
newEl = document.createElement(fragment.firstChild.tagName);
|
||||
insert.innerHTML = fragment.firstChild.innerHTML;
|
||||
newEl.appendChild(insert);
|
||||
} else {
|
||||
insert = newEl = document.createElement(fragment.firstChild.tagName);
|
||||
newEl.innerHTML = fragment.firstChild.innerHTML;
|
||||
}
|
||||
lastEl = insert;
|
||||
ice.dom.insertBefore(prevBlock, newEl);
|
||||
}
|
||||
fragment.removeChild(fragment.firstChild);
|
||||
} else {
|
||||
if(!innerBlock) {
|
||||
// Create a new block and append an insert
|
||||
newEl = document.createElement(this._ice.blockEl);
|
||||
ice.dom.insertBefore(prevBlock, newEl);
|
||||
if(this._ice.isTracking) {
|
||||
innerBlock = this._ice.createIceNode('insertType');
|
||||
this._ice.addChange('insertType', [innerBlock]);
|
||||
newEl.appendChild(innerBlock);
|
||||
} else {
|
||||
innerBlock = newEl;
|
||||
}
|
||||
}
|
||||
lastEl = innerBlock;
|
||||
innerBlock.appendChild(fragment.removeChild(fragment.firstChild));
|
||||
}
|
||||
}
|
||||
if (!newblock.textContent) {
|
||||
newblock.parentNode.removeChild(newblock);
|
||||
}
|
||||
|
||||
} else {
|
||||
if(this._ice.isTracking) {
|
||||
newEl = this._ice.createIceNode('insertType', fragment);
|
||||
this._ice.addChange('insertType', [newEl]);
|
||||
range.insertNode(newEl);
|
||||
lastEl = newEl;
|
||||
} else {
|
||||
var child;
|
||||
while((child = fragment.firstChild)) {
|
||||
range.insertNode(child);
|
||||
range.setStartAfter(child);
|
||||
range.collapse(true);
|
||||
lastEl = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._ice.endBatchChange(changeid);
|
||||
this._cleanup(lastEl);
|
||||
},
|
||||
|
||||
|
||||
createDiv: function(id) {
|
||||
var oldEl = ice.dom.getId(id);
|
||||
if(oldEl) {
|
||||
ice.dom.remove(oldEl);
|
||||
}
|
||||
|
||||
var div = this._ice.env.document.createElement('div');
|
||||
div.id = id;
|
||||
div.setAttribute('contentEditable', true);
|
||||
ice.dom.setStyle(div, 'width', '1px');
|
||||
ice.dom.setStyle(div, 'height', '1px');
|
||||
ice.dom.setStyle(div, 'overflow', 'hidden');
|
||||
ice.dom.setStyle(div, 'position', 'fixed');
|
||||
ice.dom.setStyle(div, 'top', '10px');
|
||||
ice.dom.setStyle(div, 'left', '10px');
|
||||
|
||||
document.body.appendChild(div);
|
||||
return div;
|
||||
},
|
||||
|
||||
// Intercepts cut operation and handles by creating an editable div, copying the current selection
|
||||
// into it, deleting the current selection with track changes, and selecting the contents in the
|
||||
// editable div.
|
||||
handleCut: function() {
|
||||
this.cutElementId = 'icecut';
|
||||
this.cutElement = this.createDiv(this.cutElementId);
|
||||
var range = this._ice.getCurrentRange();
|
||||
if(range.collapsed) return;
|
||||
var html = range.getHTMLContents();
|
||||
if (this._ice.isTracking) this._ice.deleteContents();
|
||||
else range.deleteContents();
|
||||
// var crange = range.cloneRange();
|
||||
// var crange = rangy.createRange();
|
||||
var crange = document.createRange();
|
||||
// crange.collapse(true);
|
||||
this.cutElement.innerHTML = html;
|
||||
|
||||
crange.setStart(this.cutElement.firstChild, 0);
|
||||
crange.setEndAfter(this.cutElement.lastChild);
|
||||
var self = this;
|
||||
|
||||
// this.cutElement.blur();
|
||||
if(this._ice.env.frame){
|
||||
// TINYMCE
|
||||
setTimeout(function(){
|
||||
self.cutElement.focus();
|
||||
|
||||
// After the browser cuts out of the `cutElement`, reset the range and remove the cut element.
|
||||
setTimeout(function() {
|
||||
ice.dom.remove(self.cutElement);
|
||||
range.setStart(range.startContainer, range.startOffset);
|
||||
range.collapse(false);
|
||||
self._ice.env.selection.addRange(range);
|
||||
// Set focus back to ice element.
|
||||
if(self._ice.env.frame) {
|
||||
self._ice.env.frame.contentWindow.focus();
|
||||
} else {
|
||||
self._ice.element.focus();
|
||||
}
|
||||
}, 100);
|
||||
}, 0);
|
||||
} else {
|
||||
// Vanilla Div
|
||||
setTimeout(function(){
|
||||
self.cutElement.focus();
|
||||
|
||||
// After the browser cuts out of the `cutElement`, reset the range and remove the cut element.
|
||||
setTimeout(function() {
|
||||
range.setStart(range.startContainer, range.startOffset);
|
||||
range.collapse(false);
|
||||
self._ice.env.selection.addRange(range);
|
||||
// Set focus back to ice element.
|
||||
if(self._ice.env.frame) {
|
||||
self._ice.env.frame.contentWindow.focus();
|
||||
} else {
|
||||
self._ice.element.focus();
|
||||
}
|
||||
}, 100);
|
||||
}, 0);
|
||||
|
||||
if(ice.dom.getWebkitType() === "chrome"){
|
||||
self.cutElement.focus();
|
||||
}
|
||||
}
|
||||
self._ice.env.selection.addRange(crange);
|
||||
},
|
||||
|
||||
|
||||
// Strips ice change tracking tags, Microsoft Word styling/content, and any
|
||||
// tags and attributes not found in `preserve` from the given `content`.
|
||||
stripPaste: function(content) {
|
||||
// Clean word stuff out and strip tags that are not in `this.preserve`.
|
||||
content = this._cleanWordPaste(content);
|
||||
content = this.cleanPreserved(content);
|
||||
return content;
|
||||
},
|
||||
|
||||
// Parses `preserve` to setup `_tags` with a comma delimited list of all of the
|
||||
// defined tags, and the `_attributesMap` with a mapping between the allowed tags and
|
||||
// an array of their allowed attributes. For example, given this value:
|
||||
// `preserve` = 'p,a[href|class],span[*]'
|
||||
// The following will result:
|
||||
// `_tags` = 'p,a,span'
|
||||
// `_attributesMap` = ['p' => [], 'a' => ['href', 'class'], 'span' => ['*']]
|
||||
setupPreserved: function() {
|
||||
var self = this;
|
||||
this._tags = '';
|
||||
this._attributesMap = [];
|
||||
|
||||
ice.dom.each(this.preserve.split(','), function(i, tagAttr) {
|
||||
// Extract the tag and attributes list
|
||||
tagAttr.match(/(\w+)(\[(.+)\])?/);
|
||||
var tag = RegExp.$1;
|
||||
var attr = RegExp.$3;
|
||||
|
||||
if(self._tags) self._tags += ',';
|
||||
self._tags += tag.toLowerCase();
|
||||
self._attributesMap[tag] = attr.split('|');
|
||||
});
|
||||
},
|
||||
|
||||
// Cleans the given `body` by removing any tags not found in `_tags` and replacing them with
|
||||
// their inner contents, and removes attributes from any tags that aren't mapped in `_attributesMap`.
|
||||
cleanPreserved: function(body) {
|
||||
var self = this;
|
||||
var bodyel = this._ice.env.document.createElement('div');
|
||||
bodyel.innerHTML = body;
|
||||
|
||||
// Strip out any tags not found in `this._tags`, replacing the tags with their inner contents.
|
||||
bodyel = ice.dom.stripEnclosingTags(bodyel, this._tags);
|
||||
|
||||
// Strip out any attributes from the allowed set of tags that don't match what is in the `_attributesMap`
|
||||
ice.dom.each(ice.dom.find(bodyel, this._tags), function(i, el) {
|
||||
if (ice.dom.hasClass(el, 'skip-clean')) {
|
||||
return true;
|
||||
}
|
||||
var tag = el.tagName.toLowerCase();
|
||||
var attrMatches = self._attributesMap[tag];
|
||||
|
||||
// Kleene star - keep all of the attributes for this tag.
|
||||
if(attrMatches[0] && attrMatches[0] === '*')
|
||||
return true;
|
||||
|
||||
// Remove any foreign attributes that do not match the map.
|
||||
if(el.hasAttributes()) {
|
||||
var attributes = el.attributes;
|
||||
for(var i = attributes.length - 1; i >= 0; i--) {
|
||||
if(!ice.dom.inArray(attributes[i].name, attrMatches)) {
|
||||
el.removeAttribute(attributes[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return bodyel.innerHTML;
|
||||
},
|
||||
|
||||
_cleanWordPaste: function(content) {
|
||||
// Meta and link tags.
|
||||
content = content.replace(/<(meta|link)[^>]+>/g, "");
|
||||
|
||||
// Comments.
|
||||
content = content.replace(/<!--(.|\s)*?-->/g, '');
|
||||
|
||||
// Remove style tags.
|
||||
content = content.replace(/<style>[\s\S]*?<\/style>/g, '');
|
||||
|
||||
// Remove span and o:p etc. tags.
|
||||
//content = content.replace(/<\/?span[^>]*>/gi, "");
|
||||
content = content.replace(/<\/?\w+:[^>]*>/gi, '' );
|
||||
|
||||
// Remove XML tags.
|
||||
content = content.replace(/<\\?\?xml[^>]*>/gi, '');
|
||||
|
||||
// Generic cleanup.
|
||||
content = this._cleanPaste(content);
|
||||
|
||||
// Remove class, lang and style attributes.
|
||||
content = content.replace(/<(\w[^>]*) (lang)=([^ |>]*)([^>]*)/gi, "<$1$4");
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
_cleanPaste: function(content) {
|
||||
// Some generic content cleanup. Change all b/i tags to strong/em.
|
||||
content = content.replace(/<b(\s+|>)/g, "<strong$1");
|
||||
content = content.replace(/<\/b(\s+|>)/g, "</strong$1");
|
||||
content = content.replace(/<i(\s+|>)/g, "<em$1");
|
||||
content = content.replace(/<\/i(\s+|>)/g, "</em$1");
|
||||
return content;
|
||||
},
|
||||
|
||||
_cleanup: function(moveTo) {
|
||||
try {
|
||||
moveTo = moveTo && moveTo.lastChild || moveTo || this._tmpNode;
|
||||
// Move the range to the end of moveTo so that the cursor will be at the end of the paste.
|
||||
var range = this._ice.getCurrentRange();
|
||||
range.setStartAfter(moveTo);
|
||||
range.collapse(true);
|
||||
this._ice.selection.addRange(range);
|
||||
// Set focus back to ice element.
|
||||
if(this._ice.env.frame) {
|
||||
this._ice.env.frame.contentWindow.focus();
|
||||
} else {
|
||||
this._ice.element.focus();
|
||||
}
|
||||
// Kill the tmp node.
|
||||
this._tmpNode.parentNode.removeChild(this._tmpNode);
|
||||
this._tmpNode = null;
|
||||
// Kill any empty change nodes.
|
||||
var ins = this._ice.env.document.getElementsByClassName(this._ice.changeTypes['insertType'].alias);
|
||||
for(var i = 0; i < ins.length; i++) {
|
||||
if(!ins[i].textContent) {
|
||||
if(ins[i].parentNode) {
|
||||
ins[i].parentNode.removeChild(ins[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
window.console && console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ice.dom.noInclusionInherits(IceCopyPastePlugin, ice.IcePlugin);
|
||||
exports._plugin.IceCopyPastePlugin = IceCopyPastePlugin;
|
||||
|
||||
}).call(this.ice);
|
||||
@@ -0,0 +1,76 @@
|
||||
(function() {
|
||||
|
||||
var exports = this;
|
||||
|
||||
/**
|
||||
* When active, this plugin will convert two successively typed dashes, within
|
||||
* the ice block element, into an emdash.
|
||||
*/
|
||||
var IceEmdashPlugin = function(ice_instance) {
|
||||
this._ice = ice_instance;
|
||||
};
|
||||
|
||||
IceEmdashPlugin.prototype = {
|
||||
|
||||
keyDown: function(e) {
|
||||
// Catch dashes.
|
||||
if(ice.dom.isBrowser('mozilla')) {
|
||||
var version = parseInt(ice.dom.browser().version);
|
||||
if ( (version > 14 && e.keyCode === 173) || (version <= 14 && e.keyCode === 109) ) {
|
||||
return this.convertEmdash(e);
|
||||
}
|
||||
} else if(e.keyCode === 189) {
|
||||
return this.convertEmdash(e);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
convertEmdash: function(e) {
|
||||
var range = this._ice.getCurrentRange();
|
||||
if(range.collapsed) {
|
||||
try {
|
||||
// Move the start back one character so we can enclose the range around the previous character to check if it is a dash
|
||||
range.moveStart(ice.dom.CHARACTER_UNIT, -1);
|
||||
// Get the parent block element for the start and end containers
|
||||
var startBlock = ice.dom.getParents(range.startContainer, this._ice.blockEl)[0];
|
||||
var endBlock = ice.dom.getParents(range.endContainer, this._ice.blockEl)[0];
|
||||
// Make sure that the start and end containers aren't in different blocks, or that the start isn't in a delete.
|
||||
if(startBlock === endBlock && !this._ice.getIceNode(range.startContainer, 'deleteType')) {
|
||||
// Get the last character and check to see if it is a dash.
|
||||
c = range.toHtml();
|
||||
if(c === '-') {
|
||||
// Extract the last character/dash and insert an emdash
|
||||
range.extractContents();
|
||||
range.collapse();
|
||||
var mdash = this._ice.env.document.createTextNode('\u2014');
|
||||
if (this._ice.isTracking) {
|
||||
this._ice._insertNode(mdash, range);
|
||||
} else {
|
||||
range.insertNode(mdash);
|
||||
/* TO be reverted once mozilla fixes FF 15 issue */
|
||||
range.setStart(mdash, 1);
|
||||
range.collapse(true);
|
||||
/* FINISH revert */
|
||||
}
|
||||
/* TO be reverted once mozilla fixes FF 15 issue
|
||||
range = this._ice.getCurrentRange();
|
||||
range.moveStart(ice.dom.CHARACTER_UNIT, 1);
|
||||
range.collapse(true);
|
||||
this._ice.env.selection.addRange(range);
|
||||
*/
|
||||
this._ice._preventKeyPress = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch(e) {}
|
||||
range.collapse();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
ice.dom.noInclusionInherits(IceEmdashPlugin, ice.IcePlugin);
|
||||
exports._plugin.IceEmdashPlugin = IceEmdashPlugin;
|
||||
|
||||
}).call(this.ice);
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
(function() {
|
||||
|
||||
var exports = this, ice = this.ice;
|
||||
|
||||
var IceSmartQuotesPlugin = function(ice_instance) {
|
||||
this._ice = ice_instance;
|
||||
};
|
||||
|
||||
IceSmartQuotesPlugin.prototype = {
|
||||
|
||||
/**
|
||||
* Finds each block in `element` and converts quotes into smart quotes.
|
||||
*/
|
||||
convert: function(element) {
|
||||
var self = this;
|
||||
try {
|
||||
self._ice.placeholdDeletes();
|
||||
ice.dom.each(element.getElementsByTagName(this._ice.blockEl), function(i, el) {
|
||||
self._convertBlock(el);
|
||||
});
|
||||
} catch(e) {
|
||||
window.console && console.error(e);
|
||||
} finally {
|
||||
self._ice.revertDeletePlaceholders();
|
||||
}
|
||||
},
|
||||
|
||||
// Converts the quotes in the given element to smart quotes.
|
||||
_convertBlock: function(el) {
|
||||
|
||||
// If there are less than 2 characters, we don't have enough to go on.
|
||||
if (ice.dom.getNodeTextContent(el) < 2) return;
|
||||
|
||||
var previous, current, next, data, html = '', getNextChar,
|
||||
regularSingle = "'",
|
||||
regularDouble = '"',
|
||||
smartSingleLeft = String.fromCharCode(8216), // aka - open curly single quote
|
||||
smartSingleRight = String.fromCharCode(8217), // aka - close curly single quote
|
||||
smartDoubleLeft = String.fromCharCode(8220), // aka - open curly double quote
|
||||
smartDoubleRight = String.fromCharCode(8221), // aka - close curly double quote
|
||||
isDigit = function(c) { return /\d/.test(c); },
|
||||
isChar = function(c) { return /\w/.test(c); },
|
||||
isSpace = function(c) { return c === String.fromCharCode(160) || c === String.fromCharCode(32); },
|
||||
isStartChar = function(c) { return isSpace(c) || c === '('; },
|
||||
isEndChar = function(c) { return isSpace(c) || c == null || c === ';' || c === ')' || c == '.' || c === '!' || c === ',' || c === '?' || c === ':'; },
|
||||
isNonSpace = function(c) { return !isSpace(c); },
|
||||
isDouble = function(c) { return c === regularDouble || c === smartDoubleLeft || c === smartDoubleRight; },
|
||||
isSingle = function(c) { return c === regularSingle || c === smartSingleLeft || c === smartSingleRight; };
|
||||
|
||||
// Split the html into array allocations with the following criteria:
|
||||
// html tags: starts with "<" and ends with ">"
|
||||
// html entities: starts with "&" and ends with ";"
|
||||
// characters: any character outside of an html tag or entity
|
||||
// So the following html:
|
||||
// n&ce <b id="bold">test</b>
|
||||
// Would split into the following array:
|
||||
// ['n', '&', 'c', 'e', ' ', '<b id="bold">', 't', 'e', 's', 't', '</b>'];
|
||||
data = ice.dom.getHtml(el).match(/(<("[^"]*"|'[^']*'|[^'">])*>|&.*;|.)/g);
|
||||
|
||||
// Searches through the `data` array from the given index a given number of
|
||||
// characters forward or backward and returns the found character.
|
||||
getNextChar = function(data, fromIndex, nCharacters) {
|
||||
var dLength = data.length,
|
||||
addWith = nCharacters < 0 ? -1 : 1;
|
||||
|
||||
return (function getChar(data, fromIndex, nCharacters) {
|
||||
// Base case - did we move outside of the bounds of the data array?
|
||||
if (fromIndex < 0 || fromIndex >= dLength) return null;
|
||||
|
||||
var next = data[fromIndex + addWith];
|
||||
|
||||
// If we find a character and we have moved through the
|
||||
// nCharacters, then the recursion is done.
|
||||
if (next && next.length == 1) {
|
||||
nCharacters += (addWith * -1);
|
||||
if (!nCharacters) return next;
|
||||
}
|
||||
return getChar(data, fromIndex + addWith, nCharacters);
|
||||
|
||||
})(data, fromIndex, nCharacters);
|
||||
};
|
||||
|
||||
ice.dom.each(data, function(pos, val) {
|
||||
// Convert space entities so that they can be processed as normal characters.
|
||||
if (val == ' ') val = data[pos] = ' ';
|
||||
|
||||
// If the val is a character, then examine the surroundings
|
||||
// and convert smart quotes, if necessary.
|
||||
if (val.length == 1) {
|
||||
|
||||
// Keep convenience pointers to the previous, current and next characters.
|
||||
previous = getNextChar(data, pos, -1);
|
||||
current = val;
|
||||
next = getNextChar(data, pos, 1);
|
||||
|
||||
switch (current) {
|
||||
|
||||
/**
|
||||
* Conversion Rules:
|
||||
* ----------------
|
||||
*
|
||||
* START: assign smart left/open
|
||||
* [SPACE|START_PARENTHESIS]'word
|
||||
* [SPACE|START_PARENTHESIS]"word
|
||||
*
|
||||
* END: assign smart right/close
|
||||
* word'[SPACE|SEMICOLON|COLON|PERIOD|COMMA|EXCLAMATION_MARK|QUESTION_MARK|END_PARENTHESIS|NULL]
|
||||
* word"[SPACE|SEMICOLON|COLON|PERIOD|COMMA|EXCLAMATION_MARK|QUESTION_MARK|END_PARENTHESIS|NULL]
|
||||
*
|
||||
* PLURAL_CONTRACTION: assign smart right/close
|
||||
* Matt's
|
||||
* can't
|
||||
* O'Reilly
|
||||
*
|
||||
* YEAR_ABBREVIATION: assign smart right/close
|
||||
* [SPACE|NULL]'99[SPACE|SEMICOLON|COLON|PERIOD|COMMA|EXCLAMATION_MARK|QUESTION_MARK|END_PARENTHESIS|NULL]
|
||||
*
|
||||
* NESTED_START: assign smart left/open
|
||||
* [SPACE|NULL]"[SPACE]'word
|
||||
*
|
||||
* NESTED_END: assign smart left/open
|
||||
* word'[SPACE]"[SPACE|SEMICOLON|COLON|PERIOD|COMMA|EXCLAMATION_MARK|QUESTION_MARK|END_PARENTHESIS|NULL]
|
||||
*
|
||||
* Notes:
|
||||
* - The following will not be converted correctly - ...word 'Til Death - it should
|
||||
* get a right/close smart quote, but will get a left/open.
|
||||
* - Distinguishing between year abbreviation, '99, and when to use an open single quote
|
||||
* could fail if a single quoted region starts with a double digit number - '99 problems'
|
||||
* - Since they are a rare case and there are many permutations, measurements are not being
|
||||
* handled (6'8", 6' 8", 6', 8").
|
||||
*/
|
||||
|
||||
// Convert smart single quotes to non-smart quote and fall through to single quote
|
||||
// handling, in case the context has changed and we need to update the smart quote.
|
||||
case smartSingleLeft:
|
||||
case smartSingleRight:
|
||||
current = regularSingle;
|
||||
case regularSingle:
|
||||
// YEAR_ABBREVIATION - look 2 ahead to see if there are two digits in a row - not fool proof
|
||||
if ((previous == null || isSpace(previous)) && isDigit(next) && isDigit(getNextChar(data, pos, 2)) && isEndChar(getNextChar(data, pos, 3)))
|
||||
current = smartSingleRight;
|
||||
// START
|
||||
else if (previous == null || (isStartChar(previous) && isNonSpace(next)))
|
||||
current = smartSingleLeft;
|
||||
// END
|
||||
else if (next == null || (isNonSpace(previous) && isEndChar(next)))
|
||||
current = smartSingleRight;
|
||||
// PLURAL_CONTRACTION
|
||||
else if (isChar(previous) && isChar(next))
|
||||
current = smartSingleRight;
|
||||
break;
|
||||
|
||||
// Convert smart double quotes to non-smart quote and fall through to double quote
|
||||
// handling, in case the context has changed and we need to update the smart quote.
|
||||
case smartDoubleLeft:
|
||||
case smartDoubleRight:
|
||||
current = regularDouble;
|
||||
case regularDouble:
|
||||
// NESTED_END
|
||||
if (isEndChar(next) && isSpace(previous) && isSingle(getNextChar(data, pos, -2)))
|
||||
current = smartDoubleRight;
|
||||
// START
|
||||
else if (previous == null || (isStartChar(previous) && isNonSpace(next)))
|
||||
current = smartDoubleLeft;
|
||||
// END
|
||||
else if (next == null || (isNonSpace(previous) && isEndChar(next)))
|
||||
current = smartDoubleRight;
|
||||
// NESTED_START
|
||||
else if ((previous == null || isSpace(previous)) && (isSpace(next) && isSingle(getNextChar(data, pos, 1))))
|
||||
current = smartDoubleLeft;
|
||||
break;
|
||||
}
|
||||
if (current != null) data[pos] = current;
|
||||
}
|
||||
});
|
||||
|
||||
ice.dom.setHtml(el, data.join(''));
|
||||
}
|
||||
};
|
||||
|
||||
ice.dom.noInclusionInherits(IceSmartQuotesPlugin, ice.IcePlugin);
|
||||
exports.ice._plugin.IceSmartQuotesPlugin = IceSmartQuotesPlugin;
|
||||
|
||||
}).call(this);
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
// Add ECMA262-5 string trim if not supported natively
|
||||
//
|
||||
if (typeof String.prototype.trim !== 'function') {
|
||||
String.prototype.trim = function() {
|
||||
return this.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Add ECMA262-5 Array methods if not supported natively
|
||||
//
|
||||
if (!('indexOf' in Array.prototype)) {
|
||||
Array.prototype.indexOf= function(find, i /*opt*/) {
|
||||
if (i===undefined) i= 0;
|
||||
if (i<0) i+= this.length;
|
||||
if (i<0) i= 0;
|
||||
for (var n= this.length; i<n; i++)
|
||||
if (i in this && this[i]===find)
|
||||
return i;
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
if (!('lastIndexOf' in Array.prototype)) {
|
||||
Array.prototype.lastIndexOf= function(find, i /*opt*/) {
|
||||
if (i===undefined) i= this.length-1;
|
||||
if (i<0) i+= this.length;
|
||||
if (i>this.length-1) i= this.length-1;
|
||||
for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */
|
||||
if (i in this && this[i]===find)
|
||||
return i;
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
if (!('map' in Array.prototype)) {
|
||||
Array.prototype.map= function(mapper, that /*opt*/) {
|
||||
var other= new Array(this.length);
|
||||
for (var i= 0, n= this.length; i<n; i++)
|
||||
if (i in this)
|
||||
other[i]= mapper.call(that, this[i], i, this);
|
||||
return other;
|
||||
};
|
||||
}
|
||||
if (!('filter' in Array.prototype)) {
|
||||
Array.prototype.filter= function(filter, that /*opt*/) {
|
||||
var other= [], v;
|
||||
for (var i=0, n= this.length; i<n; i++)
|
||||
if (i in this && filter.call(that, v= this[i], i, this))
|
||||
other.push(v);
|
||||
return other;
|
||||
};
|
||||
}
|
||||
+3224
File diff suppressed because it is too large.
Load diff
Executable
+507
@@ -0,0 +1,507 @@
|
||||
(function () {
|
||||
|
||||
var exports = this,
|
||||
Selection;
|
||||
|
||||
Selection = function (env) {
|
||||
this._selection = null;
|
||||
this.env = env;
|
||||
|
||||
this._initializeRangeLibrary();
|
||||
this._getSelection();
|
||||
};
|
||||
|
||||
Selection.prototype = {
|
||||
|
||||
/**
|
||||
* Returns the selection object for the current browser.
|
||||
*/
|
||||
_getSelection: function () {
|
||||
if (this._selection) {
|
||||
this._selection.refresh();
|
||||
}
|
||||
else if (this.env.frame) {
|
||||
this._selection = rangy.getIframeSelection(this.env.frame);
|
||||
}
|
||||
else {
|
||||
this._selection = rangy.getSelection();
|
||||
}
|
||||
return this._selection;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a range object.
|
||||
*/
|
||||
createRange: function () {
|
||||
return rangy.createRange(this.env.document);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the range object at the specified position. The current range object
|
||||
* is at position 0. Note - currently only setting single range in `addRange` so
|
||||
* position 0 will be the only allocation filled.
|
||||
*/
|
||||
getRangeAt: function (pos) {
|
||||
this._selection.refresh();
|
||||
try {
|
||||
return this._selection.getRangeAt(pos);
|
||||
}
|
||||
catch (e) {
|
||||
this._selection = null;
|
||||
return this._getSelection().getRangeAt(0);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds the specified range to the current selection. Note - only supporting setting
|
||||
* a single range, so the previous range gets evicted.
|
||||
*/
|
||||
addRange: function (range) {
|
||||
this._selection || (this._selection = this._getSelection());
|
||||
this._selection.setSingleRange(range);
|
||||
this._selection.ranges = [range];
|
||||
return;
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize and extend the `rangy` library with some custom functionality.
|
||||
*/
|
||||
_initializeRangeLibrary: function () {
|
||||
var self = this;
|
||||
|
||||
rangy.init();
|
||||
rangy.config.checkSelectionRanges = false;
|
||||
|
||||
var move = function (range, unitType, units, isStart) {
|
||||
if (units === 0) {
|
||||
throw Error('InvalidArgumentException: units cannot be 0');
|
||||
}
|
||||
|
||||
switch (unitType) {
|
||||
case ice.dom.CHARACTER_UNIT:
|
||||
if (units > 0) {
|
||||
range.moveCharRight(isStart, units);
|
||||
} else {
|
||||
range.moveCharLeft(isStart, units * -1);
|
||||
}
|
||||
break;
|
||||
|
||||
case ice.dom.WORD_UNIT:
|
||||
default:
|
||||
// Removed. TODO: possibly refactor or re-implement.
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves the start of the range using the specified `unitType`, by the specified
|
||||
* number of `units`. Defaults to `CHARACTER_UNIT` and units of 1.
|
||||
*/
|
||||
rangy.rangePrototype.moveStart = function (unitType, units) {
|
||||
move(this, unitType, units, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves the end of the range using the specified `unitType`, by the specified
|
||||
* number of `units`.
|
||||
*/
|
||||
rangy.rangePrototype.moveEnd = function (unitType, units) {
|
||||
move(this, unitType, units, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Depending on the given `start` boolean, sets the start or end containers
|
||||
* to the given `container` with `offset` units.
|
||||
*/
|
||||
rangy.rangePrototype.setRange = function (start, container, offset) {
|
||||
if (start) {
|
||||
this.setStart(container, offset);
|
||||
} else {
|
||||
this.setEnd(container, offset);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Depending on the given `moveStart` boolean, moves the start or end containers
|
||||
* to the left by the given number of character `units`. Use the following
|
||||
* example as a demonstration for where the range will fall as it moves in and
|
||||
* out of tag boundaries (where "|" is the marked range):
|
||||
*
|
||||
* test <em>it</em> o|ut
|
||||
* test <em>it</em> |out
|
||||
* test <em>it</em>| out
|
||||
* test <em>i|t</em> out
|
||||
* test <em>|it</em> out
|
||||
* test| <em>it</em> out
|
||||
* tes|t <em>it</em> out
|
||||
*
|
||||
* A range could be mapped in one of two ways:
|
||||
*
|
||||
* (1) If a startContainer is a Node of type Text, Comment, or CDATASection, then startOffset
|
||||
* is the number of characters from the start of startNode. For example, the following
|
||||
* are the range properties for `<p>te|st</p>` (where "|" is the collapsed range):
|
||||
*
|
||||
* startContainer: <TEXT>test<TEXT>
|
||||
* startOffset: 2
|
||||
* endContainer: <TEXT>test<TEXT>
|
||||
* endOffset: 2
|
||||
*
|
||||
* (2) For other Node types, startOffset is the number of child nodes between the start of
|
||||
* the startNode. Take the following html fragment:
|
||||
*
|
||||
* `<p>some <span>test</span> text</p>`
|
||||
*
|
||||
* If we were working with the following range properties:
|
||||
*
|
||||
* startContainer: <p>
|
||||
* startOffset: 2
|
||||
* endContainer: <p>
|
||||
* endOffset: 2
|
||||
*
|
||||
* Since <p> is an Element node, the offsets are based on the offset in child nodes of <p> and
|
||||
* the range is selecting the second child - the <span> tag.
|
||||
*
|
||||
* <p><TEXT>some </TEXT><SPAN>test</SPAN><TEXT> text</TEXT></p>
|
||||
*/
|
||||
rangy.rangePrototype.moveCharLeft = function (moveStart, units) {
|
||||
var container, offset;
|
||||
|
||||
if (moveStart) {
|
||||
container = this.startContainer;
|
||||
offset = this.startOffset;
|
||||
} else {
|
||||
container = this.endContainer;
|
||||
offset = this.endOffset;
|
||||
}
|
||||
|
||||
// Handle the case where the range conforms to (2) (noted in the comment above).
|
||||
if (container.nodeType === ice.dom.ELEMENT_NODE) {
|
||||
if (container.hasChildNodes()) {
|
||||
container = container.childNodes[offset];
|
||||
|
||||
container = this.getPreviousTextNode(container);
|
||||
|
||||
// Get the previous text container that is not an empty text node.
|
||||
while (container && container.nodeType == ice.dom.TEXT_NODE && container.nodeValue === "") {
|
||||
container = this.getPreviousTextNode(container);
|
||||
}
|
||||
|
||||
offset = container.data.length - units;
|
||||
} else {
|
||||
offset = units * -1;
|
||||
}
|
||||
} else {
|
||||
offset -= units;
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
// We need to move to a previous selectable container.
|
||||
while (offset < 0) {
|
||||
var skippedBlockElem = [];
|
||||
|
||||
container = this.getPreviousTextNode(container, skippedBlockElem);
|
||||
|
||||
// We are at the beginning/out of the editable - break.
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (container.nodeType === ice.dom.ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
offset += container.data.length;
|
||||
}
|
||||
}
|
||||
|
||||
this.setRange(moveStart, container, offset);
|
||||
};
|
||||
|
||||
/**
|
||||
* Depending on the given `moveStart` boolean, moves the start or end containers
|
||||
* to the right by the given number of character `units`. Use the following
|
||||
* example as a demonstration for where the range will fall as it moves in and
|
||||
* out of tag boundaries (where "|" is the marked range):
|
||||
*
|
||||
* tes|t <em>it</em> out
|
||||
* test| <em>it</em> out
|
||||
* test |<em>it</em> out
|
||||
* test <em>i|t</em> out
|
||||
* test <em>it|</em> out
|
||||
* test <em>it</em> |out
|
||||
*
|
||||
* A range could be mapped in one of two ways:
|
||||
*
|
||||
* (1) If a startContainer is a Node of type Text, Comment, or CDATASection, then startOffset
|
||||
* is the number of characters from the start of startNode. For example, the following
|
||||
* are the range properties for `<p>te|st</p>` (where "|" is the collapsed range):
|
||||
*
|
||||
* startContainer: <TEXT>test<TEXT>
|
||||
* startOffset: 2
|
||||
* endContainer: <TEXT>test<TEXT>
|
||||
* endOffset: 2
|
||||
*
|
||||
* (2) For other Node types, startOffset is the number of child nodes between the start of
|
||||
* the startNode. Take the following html fragment:
|
||||
*
|
||||
* `<p>some <span>test</span> text</p>`
|
||||
*
|
||||
* If we were working with the following range properties:
|
||||
*
|
||||
* startContainer: <p>
|
||||
* startOffset: 2
|
||||
* endContainer: <p>
|
||||
* endOffset: 2
|
||||
*
|
||||
* Since <p> is an Element node, the offsets are based on the offset in child nodes of <p> and
|
||||
* the range is selecting the second child - the <span> tag.
|
||||
*
|
||||
* <p><TEXT>some </TEXT><SPAN>test</SPAN><TEXT> text</TEXT></p>
|
||||
*/
|
||||
rangy.rangePrototype.moveCharRight = function (moveStart, units) {
|
||||
var container, offset;
|
||||
|
||||
if (moveStart) {
|
||||
container = this.startContainer;
|
||||
offset = this.startOffset;
|
||||
} else {
|
||||
container = this.endContainer;
|
||||
offset = this.endOffset;
|
||||
}
|
||||
|
||||
if (container.nodeType === ice.dom.ELEMENT_NODE) {
|
||||
container = container.childNodes[offset];
|
||||
if (container.nodeType !== ice.dom.TEXT_NODE) {
|
||||
container = this.getNextTextNode(container);
|
||||
}
|
||||
|
||||
offset = units;
|
||||
} else {
|
||||
offset += units;
|
||||
}
|
||||
|
||||
var diff = (offset - container.data.length);
|
||||
if (diff > 0) {
|
||||
var skippedBlockElem = [];
|
||||
// We need to move to the next selectable container.
|
||||
while (diff > 0) {
|
||||
container = this.getNextContainer(container, skippedBlockElem);
|
||||
|
||||
if (container.nodeType === ice.dom.ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (container.data.length >= diff) {
|
||||
// We found a container with enough content to select.
|
||||
break;
|
||||
} else if (container.data.length > 0) {
|
||||
// Container does not have enough content,
|
||||
// find the next one.
|
||||
diff -= container.data.length;
|
||||
}
|
||||
}
|
||||
|
||||
offset = diff;
|
||||
}
|
||||
|
||||
this.setRange(moveStart, container, offset);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the deepest next container that the range can be extended to.
|
||||
* For example, if the next container is an element that contains text nodes,
|
||||
* the the container's firstChild is returned.
|
||||
*/
|
||||
rangy.rangePrototype.getNextContainer = function (container, skippedBlockElem) {
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (container.nextSibling) {
|
||||
container = container.nextSibling;
|
||||
if (container.nodeType !== ice.dom.TEXT_NODE) {
|
||||
var child = this.getFirstSelectableChild(container);
|
||||
if (child !== null) {
|
||||
return child;
|
||||
}
|
||||
} else if (this.isSelectable(container) === true) {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
// Look at parents next sibling.
|
||||
while (container && !container.nextSibling) {
|
||||
container = container.parentNode;
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
container = container.nextSibling;
|
||||
if (this.isSelectable(container) === true) {
|
||||
return container;
|
||||
} else if (skippedBlockElem && ice.dom.isBlockElement(container) === true) {
|
||||
skippedBlockElem.push(container);
|
||||
}
|
||||
|
||||
var selChild = this.getFirstSelectableChild(container);
|
||||
if (selChild !== null) {
|
||||
return selChild;
|
||||
}
|
||||
|
||||
return this.getNextContainer(container, skippedBlockElem);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the deepest previous container that the range can be extended to.
|
||||
* For example, if the previous container is an element that contains text nodes,
|
||||
* then the container's lastChild is returned.
|
||||
*/
|
||||
rangy.rangePrototype.getPreviousContainer = function (container, skippedBlockElem) {
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (container.previousSibling) {
|
||||
container = container.previousSibling;
|
||||
if (container.nodeType !== ice.dom.TEXT_NODE) {
|
||||
if (ice.dom.isStubElement(container) === true) {
|
||||
return container;
|
||||
} else {
|
||||
var child = this.getLastSelectableChild(container);
|
||||
if (child !== null) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
} else if (this.isSelectable(container) === true) {
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
// Look at parents next sibling.
|
||||
while (container && !container.previousSibling) {
|
||||
container = container.parentNode;
|
||||
}
|
||||
|
||||
if (!container) {
|
||||
return null;
|
||||
}
|
||||
|
||||
container = container.previousSibling;
|
||||
if (this.isSelectable(container) === true) {
|
||||
return container;
|
||||
} else if (skippedBlockElem && ice.dom.isBlockElement(container) === true) {
|
||||
skippedBlockElem.push(container);
|
||||
}
|
||||
|
||||
var selChild = this.getLastSelectableChild(container);
|
||||
if (selChild !== null) {
|
||||
return selChild;
|
||||
}
|
||||
return this.getPreviousContainer(container, skippedBlockElem);
|
||||
};
|
||||
|
||||
rangy.rangePrototype.getNextTextNode = function (container) {
|
||||
if (container.nodeType === ice.dom.ELEMENT_NODE) {
|
||||
if (container.childNodes.length !== 0) {
|
||||
return this.getFirstSelectableChild(container);
|
||||
}
|
||||
}
|
||||
|
||||
container = this.getNextContainer(container);
|
||||
if (container.nodeType === ice.dom.TEXT_NODE) {
|
||||
return container;
|
||||
}
|
||||
|
||||
return this.getNextTextNode(container);
|
||||
};
|
||||
|
||||
rangy.rangePrototype.getPreviousTextNode = function (container, skippedBlockEl) {
|
||||
container = this.getPreviousContainer(container, skippedBlockEl);
|
||||
if (container.nodeType === ice.dom.TEXT_NODE) {
|
||||
return container;
|
||||
}
|
||||
|
||||
return this.getPreviousTextNode(container, skippedBlockEl);
|
||||
};
|
||||
|
||||
rangy.rangePrototype.getFirstSelectableChild = function (element) {
|
||||
if (element) {
|
||||
if (element.nodeType !== ice.dom.TEXT_NODE) {
|
||||
var child = element.firstChild;
|
||||
while (child) {
|
||||
if (this.isSelectable(child) === true) {
|
||||
return child;
|
||||
} else if (child.firstChild) {
|
||||
// This node does have child nodes.
|
||||
var res = this.getFirstSelectableChild(child);
|
||||
if (res !== null) {
|
||||
return res;
|
||||
} else {
|
||||
child = child.nextSibling;
|
||||
}
|
||||
} else {
|
||||
child = child.nextSibling;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Given element is a text node so return it.
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
rangy.rangePrototype.getLastSelectableChild = function (element) {
|
||||
if (element) {
|
||||
if (element.nodeType !== ice.dom.TEXT_NODE) {
|
||||
var child = element.lastChild;
|
||||
while (child) {
|
||||
if (this.isSelectable(child) === true) {
|
||||
return child;
|
||||
} else if (child.lastChild) {
|
||||
// This node does have child nodes.
|
||||
var res = this.getLastSelectableChild(child);
|
||||
if (res !== null) {
|
||||
return res;
|
||||
} else {
|
||||
child = child.previousSibling;
|
||||
}
|
||||
} else {
|
||||
child = child.previousSibling;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Given element is a text node so return it.
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
rangy.rangePrototype.isSelectable = function (container) {
|
||||
if (container && container.nodeType === ice.dom.TEXT_NODE && container.data.length !== 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
rangy.rangePrototype.getHTMLContents = function (clonedSelection) {
|
||||
if (!clonedSelection) {
|
||||
clonedSelection = this.cloneContents();
|
||||
}
|
||||
var div = self.env.document.createElement('div');
|
||||
div.appendChild(clonedSelection.cloneNode(true));
|
||||
return div.innerHTML;
|
||||
};
|
||||
|
||||
rangy.rangePrototype.getHTMLContentsObj = function () {
|
||||
return this.cloneContents();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
exports.Selection = Selection;
|
||||
|
||||
}).call(this.ice);
|
||||
Reference in new issue
Block a user