tinymce-rails 4.0.16 → 4.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/app/assets/source/tinymce/tinymce.jquery.js +3060 -2879
- data/app/assets/source/tinymce/tinymce.js +1386 -1205
- data/lib/tinymce/rails/configuration.rb +15 -1
- data/lib/tinymce/rails/helper.rb +4 -4
- data/lib/tinymce/rails/version.rb +2 -2
- data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/contextmenu/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/fullpage/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/nonbreaking/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/spellchecker/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/textcolor/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/wordcount/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/lightgray/content.inline.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/lightgray/content.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
- data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +10 -9
- data/vendor/assets/javascripts/tinymce/tinymce.js +10 -10
- metadata +13 -18
@@ -1,4 +1,4 @@
|
|
1
|
-
// 4.0.
|
1
|
+
// 4.0.18 (2014-02-27)
|
2
2
|
|
3
3
|
/**
|
4
4
|
* Compiled inline version. (Library mode)
|
@@ -192,7 +192,7 @@ define("tinymce/dom/EventUtils", [], function() {
|
|
192
192
|
} else {
|
193
193
|
originalEvent.cancelBubble = true; // IE
|
194
194
|
}
|
195
|
-
|
195
|
+
}
|
196
196
|
};
|
197
197
|
|
198
198
|
// Add stopImmediatePropagation
|
@@ -232,7 +232,9 @@ define("tinymce/dom/EventUtils", [], function() {
|
|
232
232
|
}
|
233
233
|
|
234
234
|
function waitForDomLoaded() {
|
235
|
-
|
235
|
+
// Check complete or interactive state if there is a body
|
236
|
+
// element on some iframes IE 8 will produce a null body
|
237
|
+
if (doc.readyState === "complete" || (doc.readyState === "interactive" && doc.body)) {
|
236
238
|
removeEvent(doc, "readystatechange", waitForDomLoaded);
|
237
239
|
readyHandler();
|
238
240
|
}
|
@@ -4604,7 +4606,7 @@ define("tinymce/dom/Range", [
|
|
4604
4606
|
return _traverseCommonAncestors(startNode, endNode, how);
|
4605
4607
|
}
|
4606
4608
|
|
4607
|
-
|
4609
|
+
function _traverseSameContainer(how) {
|
4608
4610
|
var frag, s, sub, n, cnt, sibling, xferNode, start, len;
|
4609
4611
|
|
4610
4612
|
if (how != DELETE) {
|
@@ -5392,190 +5394,190 @@ define("tinymce/Env", [], function() {
|
|
5392
5394
|
|
5393
5395
|
// Included from: js/tinymce/classes/dom/StyleSheetLoader.js
|
5394
5396
|
|
5395
|
-
/**
|
5396
|
-
* StyleSheetLoader.js
|
5397
|
-
*
|
5398
|
-
* Copyright, Moxiecode Systems AB
|
5399
|
-
* Released under LGPL License.
|
5400
|
-
*
|
5401
|
-
* License: http://www.tinymce.com/license
|
5402
|
-
* Contributing: http://www.tinymce.com/contributing
|
5403
|
-
*/
|
5404
|
-
|
5405
|
-
/**
|
5406
|
-
* This class handles loading of external stylesheets and fires events when these are loaded.
|
5407
|
-
*
|
5408
|
-
* @class tinymce.dom.StyleSheetLoader
|
5409
|
-
* @private
|
5410
|
-
*/
|
5411
|
-
define("tinymce/dom/StyleSheetLoader", [], function() {
|
5412
|
-
"use strict";
|
5413
|
-
|
5414
|
-
return function(document, settings) {
|
5415
|
-
var idCount = 0, loadedStates = {}, maxLoadTime;
|
5416
|
-
|
5417
|
-
settings = settings || {};
|
5418
|
-
maxLoadTime = settings.maxLoadTime || 5000;
|
5419
|
-
|
5420
|
-
function appendToHead(node) {
|
5421
|
-
document.getElementsByTagName('head')[0].appendChild(node);
|
5422
|
-
}
|
5423
|
-
|
5424
|
-
/**
|
5425
|
-
* Loads the specified css style sheet file and call the loadedCallback once it's finished loading.
|
5426
|
-
*
|
5427
|
-
* @method load
|
5428
|
-
* @param {String} url Url to be loaded.
|
5429
|
-
* @param {Function} loadedCallback Callback to be executed when loaded.
|
5430
|
-
* @param {Function} errorCallback Callback to be executed when failed loading.
|
5431
|
-
*/
|
5432
|
-
function load(url, loadedCallback, errorCallback) {
|
5433
|
-
var link, style, startTime, state;
|
5434
|
-
|
5435
|
-
function passed() {
|
5436
|
-
var callbacks = state.passed, i = callbacks.length;
|
5437
|
-
|
5438
|
-
while (i--) {
|
5439
|
-
callbacks[i]();
|
5440
|
-
}
|
5441
|
-
|
5442
|
-
state.status = 2;
|
5443
|
-
state.passed = [];
|
5444
|
-
state.failed = [];
|
5445
|
-
}
|
5446
|
-
|
5447
|
-
function failed() {
|
5448
|
-
var callbacks = state.failed, i = callbacks.length;
|
5449
|
-
|
5450
|
-
while (i--) {
|
5451
|
-
callbacks[i]();
|
5452
|
-
}
|
5453
|
-
|
5454
|
-
state.status = 3;
|
5455
|
-
state.passed = [];
|
5456
|
-
state.failed = [];
|
5457
|
-
}
|
5458
|
-
|
5459
|
-
// Sniffs for older WebKit versions that have the link.onload but a broken one
|
5460
|
-
function isOldWebKit() {
|
5461
|
-
var webKitChunks = navigator.userAgent.match(/WebKit\/(\d*)/);
|
5462
|
-
return !!(webKitChunks && webKitChunks[1] < 536);
|
5463
|
-
}
|
5464
|
-
|
5465
|
-
// Calls the waitCallback until the test returns true or the timeout occurs
|
5466
|
-
function wait(testCallback, waitCallback) {
|
5467
|
-
if (!testCallback()) {
|
5468
|
-
// Wait for timeout
|
5469
|
-
if ((new Date().getTime()) - startTime < maxLoadTime) {
|
5470
|
-
window.setTimeout(waitCallback, 0);
|
5471
|
-
} else {
|
5472
|
-
failed();
|
5473
|
-
}
|
5474
|
-
}
|
5475
|
-
}
|
5476
|
-
|
5477
|
-
// Workaround for WebKit that doesn't properly support the onload event for link elements
|
5478
|
-
// Or WebKit that fires the onload event before the StyleSheet is added to the document
|
5479
|
-
function waitForWebKitLinkLoaded() {
|
5480
|
-
wait(function() {
|
5481
|
-
var styleSheets = document.styleSheets, styleSheet, i = styleSheets.length, owner;
|
5482
|
-
|
5483
|
-
while (i--) {
|
5484
|
-
styleSheet = styleSheets[i];
|
5485
|
-
owner = styleSheet.ownerNode ? styleSheet.ownerNode : styleSheet.owningElement;
|
5486
|
-
if (owner && owner.id === link.id) {
|
5487
|
-
passed();
|
5488
|
-
return true;
|
5489
|
-
}
|
5490
|
-
}
|
5491
|
-
}, waitForWebKitLinkLoaded);
|
5492
|
-
}
|
5493
|
-
|
5494
|
-
// Workaround for older Geckos that doesn't have any onload event for StyleSheets
|
5495
|
-
function waitForGeckoLinkLoaded() {
|
5496
|
-
wait(function() {
|
5497
|
-
try {
|
5498
|
-
// Accessing the cssRules will throw an exception until the CSS file is loaded
|
5499
|
-
var cssRules = style.sheet.cssRules;
|
5500
|
-
passed();
|
5501
|
-
return !!cssRules;
|
5502
|
-
} catch (ex) {
|
5503
|
-
// Ignore
|
5504
|
-
}
|
5505
|
-
}, waitForGeckoLinkLoaded);
|
5506
|
-
}
|
5507
|
-
|
5508
|
-
if (!loadedStates[url]) {
|
5509
|
-
state = {
|
5510
|
-
passed: [],
|
5511
|
-
failed: []
|
5512
|
-
};
|
5513
|
-
|
5514
|
-
loadedStates[url] = state;
|
5515
|
-
} else {
|
5516
|
-
state = loadedStates[url];
|
5517
|
-
}
|
5518
|
-
|
5519
|
-
if (loadedCallback) {
|
5520
|
-
state.passed.push(loadedCallback);
|
5521
|
-
}
|
5522
|
-
|
5523
|
-
if (errorCallback) {
|
5524
|
-
state.failed.push(errorCallback);
|
5525
|
-
}
|
5526
|
-
|
5527
|
-
// Is loading wait for it to pass
|
5528
|
-
if (state.status == 1) {
|
5529
|
-
return;
|
5530
|
-
}
|
5531
|
-
|
5532
|
-
// Has finished loading and was success
|
5533
|
-
if (state.status == 2) {
|
5534
|
-
passed();
|
5535
|
-
return;
|
5536
|
-
}
|
5537
|
-
|
5538
|
-
// Has finished loading and was a failure
|
5539
|
-
if (state.status == 3) {
|
5540
|
-
failed();
|
5541
|
-
return;
|
5542
|
-
}
|
5543
|
-
|
5544
|
-
// Start loading
|
5545
|
-
state.status = 1;
|
5546
|
-
link = document.createElement('link');
|
5547
|
-
link.rel = 'stylesheet';
|
5548
|
-
link.type = 'text/css';
|
5549
|
-
link.id = 'u' + (idCount++);
|
5550
|
-
link.async = false;
|
5551
|
-
link.defer = false;
|
5552
|
-
startTime = new Date().getTime();
|
5553
|
-
|
5554
|
-
// Feature detect onload on link element and sniff older webkits since it has an broken onload event
|
5555
|
-
if ("onload" in link && !isOldWebKit()) {
|
5556
|
-
link.onload = waitForWebKitLinkLoaded;
|
5557
|
-
link.onerror = failed;
|
5558
|
-
} else {
|
5559
|
-
// Sniff for old Firefox that doesn't support the onload event on link elements
|
5560
|
-
// TODO: Remove this in the future when everyone uses modern browsers
|
5561
|
-
if (navigator.userAgent.indexOf("Firefox") > 0) {
|
5562
|
-
style = document.createElement('style');
|
5563
|
-
style.textContent = '@import "' + url + '"';
|
5564
|
-
waitForGeckoLinkLoaded();
|
5565
|
-
appendToHead(style);
|
5566
|
-
return;
|
5567
|
-
} else {
|
5568
|
-
// Use the id owner on older webkits
|
5569
|
-
waitForWebKitLinkLoaded();
|
5570
|
-
}
|
5571
|
-
}
|
5572
|
-
|
5573
|
-
appendToHead(link);
|
5574
|
-
link.href = url;
|
5575
|
-
}
|
5576
|
-
|
5577
|
-
this.load = load;
|
5578
|
-
};
|
5397
|
+
/**
|
5398
|
+
* StyleSheetLoader.js
|
5399
|
+
*
|
5400
|
+
* Copyright, Moxiecode Systems AB
|
5401
|
+
* Released under LGPL License.
|
5402
|
+
*
|
5403
|
+
* License: http://www.tinymce.com/license
|
5404
|
+
* Contributing: http://www.tinymce.com/contributing
|
5405
|
+
*/
|
5406
|
+
|
5407
|
+
/**
|
5408
|
+
* This class handles loading of external stylesheets and fires events when these are loaded.
|
5409
|
+
*
|
5410
|
+
* @class tinymce.dom.StyleSheetLoader
|
5411
|
+
* @private
|
5412
|
+
*/
|
5413
|
+
define("tinymce/dom/StyleSheetLoader", [], function() {
|
5414
|
+
"use strict";
|
5415
|
+
|
5416
|
+
return function(document, settings) {
|
5417
|
+
var idCount = 0, loadedStates = {}, maxLoadTime;
|
5418
|
+
|
5419
|
+
settings = settings || {};
|
5420
|
+
maxLoadTime = settings.maxLoadTime || 5000;
|
5421
|
+
|
5422
|
+
function appendToHead(node) {
|
5423
|
+
document.getElementsByTagName('head')[0].appendChild(node);
|
5424
|
+
}
|
5425
|
+
|
5426
|
+
/**
|
5427
|
+
* Loads the specified css style sheet file and call the loadedCallback once it's finished loading.
|
5428
|
+
*
|
5429
|
+
* @method load
|
5430
|
+
* @param {String} url Url to be loaded.
|
5431
|
+
* @param {Function} loadedCallback Callback to be executed when loaded.
|
5432
|
+
* @param {Function} errorCallback Callback to be executed when failed loading.
|
5433
|
+
*/
|
5434
|
+
function load(url, loadedCallback, errorCallback) {
|
5435
|
+
var link, style, startTime, state;
|
5436
|
+
|
5437
|
+
function passed() {
|
5438
|
+
var callbacks = state.passed, i = callbacks.length;
|
5439
|
+
|
5440
|
+
while (i--) {
|
5441
|
+
callbacks[i]();
|
5442
|
+
}
|
5443
|
+
|
5444
|
+
state.status = 2;
|
5445
|
+
state.passed = [];
|
5446
|
+
state.failed = [];
|
5447
|
+
}
|
5448
|
+
|
5449
|
+
function failed() {
|
5450
|
+
var callbacks = state.failed, i = callbacks.length;
|
5451
|
+
|
5452
|
+
while (i--) {
|
5453
|
+
callbacks[i]();
|
5454
|
+
}
|
5455
|
+
|
5456
|
+
state.status = 3;
|
5457
|
+
state.passed = [];
|
5458
|
+
state.failed = [];
|
5459
|
+
}
|
5460
|
+
|
5461
|
+
// Sniffs for older WebKit versions that have the link.onload but a broken one
|
5462
|
+
function isOldWebKit() {
|
5463
|
+
var webKitChunks = navigator.userAgent.match(/WebKit\/(\d*)/);
|
5464
|
+
return !!(webKitChunks && webKitChunks[1] < 536);
|
5465
|
+
}
|
5466
|
+
|
5467
|
+
// Calls the waitCallback until the test returns true or the timeout occurs
|
5468
|
+
function wait(testCallback, waitCallback) {
|
5469
|
+
if (!testCallback()) {
|
5470
|
+
// Wait for timeout
|
5471
|
+
if ((new Date().getTime()) - startTime < maxLoadTime) {
|
5472
|
+
window.setTimeout(waitCallback, 0);
|
5473
|
+
} else {
|
5474
|
+
failed();
|
5475
|
+
}
|
5476
|
+
}
|
5477
|
+
}
|
5478
|
+
|
5479
|
+
// Workaround for WebKit that doesn't properly support the onload event for link elements
|
5480
|
+
// Or WebKit that fires the onload event before the StyleSheet is added to the document
|
5481
|
+
function waitForWebKitLinkLoaded() {
|
5482
|
+
wait(function() {
|
5483
|
+
var styleSheets = document.styleSheets, styleSheet, i = styleSheets.length, owner;
|
5484
|
+
|
5485
|
+
while (i--) {
|
5486
|
+
styleSheet = styleSheets[i];
|
5487
|
+
owner = styleSheet.ownerNode ? styleSheet.ownerNode : styleSheet.owningElement;
|
5488
|
+
if (owner && owner.id === link.id) {
|
5489
|
+
passed();
|
5490
|
+
return true;
|
5491
|
+
}
|
5492
|
+
}
|
5493
|
+
}, waitForWebKitLinkLoaded);
|
5494
|
+
}
|
5495
|
+
|
5496
|
+
// Workaround for older Geckos that doesn't have any onload event for StyleSheets
|
5497
|
+
function waitForGeckoLinkLoaded() {
|
5498
|
+
wait(function() {
|
5499
|
+
try {
|
5500
|
+
// Accessing the cssRules will throw an exception until the CSS file is loaded
|
5501
|
+
var cssRules = style.sheet.cssRules;
|
5502
|
+
passed();
|
5503
|
+
return !!cssRules;
|
5504
|
+
} catch (ex) {
|
5505
|
+
// Ignore
|
5506
|
+
}
|
5507
|
+
}, waitForGeckoLinkLoaded);
|
5508
|
+
}
|
5509
|
+
|
5510
|
+
if (!loadedStates[url]) {
|
5511
|
+
state = {
|
5512
|
+
passed: [],
|
5513
|
+
failed: []
|
5514
|
+
};
|
5515
|
+
|
5516
|
+
loadedStates[url] = state;
|
5517
|
+
} else {
|
5518
|
+
state = loadedStates[url];
|
5519
|
+
}
|
5520
|
+
|
5521
|
+
if (loadedCallback) {
|
5522
|
+
state.passed.push(loadedCallback);
|
5523
|
+
}
|
5524
|
+
|
5525
|
+
if (errorCallback) {
|
5526
|
+
state.failed.push(errorCallback);
|
5527
|
+
}
|
5528
|
+
|
5529
|
+
// Is loading wait for it to pass
|
5530
|
+
if (state.status == 1) {
|
5531
|
+
return;
|
5532
|
+
}
|
5533
|
+
|
5534
|
+
// Has finished loading and was success
|
5535
|
+
if (state.status == 2) {
|
5536
|
+
passed();
|
5537
|
+
return;
|
5538
|
+
}
|
5539
|
+
|
5540
|
+
// Has finished loading and was a failure
|
5541
|
+
if (state.status == 3) {
|
5542
|
+
failed();
|
5543
|
+
return;
|
5544
|
+
}
|
5545
|
+
|
5546
|
+
// Start loading
|
5547
|
+
state.status = 1;
|
5548
|
+
link = document.createElement('link');
|
5549
|
+
link.rel = 'stylesheet';
|
5550
|
+
link.type = 'text/css';
|
5551
|
+
link.id = 'u' + (idCount++);
|
5552
|
+
link.async = false;
|
5553
|
+
link.defer = false;
|
5554
|
+
startTime = new Date().getTime();
|
5555
|
+
|
5556
|
+
// Feature detect onload on link element and sniff older webkits since it has an broken onload event
|
5557
|
+
if ("onload" in link && !isOldWebKit()) {
|
5558
|
+
link.onload = waitForWebKitLinkLoaded;
|
5559
|
+
link.onerror = failed;
|
5560
|
+
} else {
|
5561
|
+
// Sniff for old Firefox that doesn't support the onload event on link elements
|
5562
|
+
// TODO: Remove this in the future when everyone uses modern browsers
|
5563
|
+
if (navigator.userAgent.indexOf("Firefox") > 0) {
|
5564
|
+
style = document.createElement('style');
|
5565
|
+
style.textContent = '@import "' + url + '"';
|
5566
|
+
waitForGeckoLinkLoaded();
|
5567
|
+
appendToHead(style);
|
5568
|
+
return;
|
5569
|
+
} else {
|
5570
|
+
// Use the id owner on older webkits
|
5571
|
+
waitForWebKitLinkLoaded();
|
5572
|
+
}
|
5573
|
+
}
|
5574
|
+
|
5575
|
+
appendToHead(link);
|
5576
|
+
link.href = url;
|
5577
|
+
}
|
5578
|
+
|
5579
|
+
this.load = load;
|
5580
|
+
};
|
5579
5581
|
});
|
5580
5582
|
|
5581
5583
|
// Included from: js/tinymce/classes/dom/DOMUtils.js
|
@@ -9052,7 +9054,7 @@ define("tinymce/html/Schema", [
|
|
9052
9054
|
textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
|
9053
9055
|
'blockquote center dir fieldset header footer article section hgroup aside nav figure');
|
9054
9056
|
blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
|
9055
|
-
'th tr td li ol ul caption dl dt dd noscript menu isindex
|
9057
|
+
'th tr td li ol ul caption dl dt dd noscript menu isindex option ' +
|
9056
9058
|
'datalist select optgroup', textBlockElementsMap);
|
9057
9059
|
|
9058
9060
|
each((settings.special || 'script noscript style textarea').split(' '), function(name) {
|
@@ -9566,7 +9568,7 @@ define("tinymce/html/Schema", [
|
|
9566
9568
|
|
9567
9569
|
/**
|
9568
9570
|
* Parses a valid elements string and adds it to the schema. The valid elements
|
9569
|
-
|
9571
|
+
* format is for example "element[attr=default|otherattr]".
|
9570
9572
|
* Existing rules will be replaced with the ones specified, so this extends the schema.
|
9571
9573
|
*
|
9572
9574
|
* @method addValidElements
|
@@ -12273,8 +12275,6 @@ define("tinymce/dom/ControlSelection", [
|
|
12273
12275
|
var handleElm, handlerContainerElm;
|
12274
12276
|
|
12275
12277
|
function startDrag(e) {
|
12276
|
-
resizeStarted = true;
|
12277
|
-
|
12278
12278
|
startX = e.screenX;
|
12279
12279
|
startY = e.screenY;
|
12280
12280
|
startW = selectedElm.clientWidth;
|
@@ -12322,12 +12322,18 @@ define("tinymce/dom/ControlSelection", [
|
|
12322
12322
|
id: 'mceResizeHandle' + name,
|
12323
12323
|
'data-mce-bogus': true,
|
12324
12324
|
'class': 'mce-resizehandle',
|
12325
|
-
|
12326
|
-
unSelectabe: true,
|
12325
|
+
unselectable: true,
|
12327
12326
|
style: 'cursor:' + name + '-resize; margin:0; padding:0'
|
12328
12327
|
});
|
12329
12328
|
|
12329
|
+
// Hides IE move layer cursor
|
12330
|
+
// If we set it on Chrome we get this wounderful bug: #6725
|
12331
|
+
if (Env.ie) {
|
12332
|
+
handleElm.contentEditable = false;
|
12333
|
+
}
|
12334
|
+
|
12330
12335
|
dom.bind(handleElm, 'mousedown', function(e) {
|
12336
|
+
e.stopImmediatePropagation();
|
12331
12337
|
e.preventDefault();
|
12332
12338
|
startDrag(e);
|
12333
12339
|
});
|
@@ -12568,6 +12574,485 @@ define("tinymce/dom/ControlSelection", [
|
|
12568
12574
|
};
|
12569
12575
|
});
|
12570
12576
|
|
12577
|
+
// Included from: js/tinymce/classes/dom/RangeUtils.js
|
12578
|
+
|
12579
|
+
/**
|
12580
|
+
* Range.js
|
12581
|
+
*
|
12582
|
+
* Copyright, Moxiecode Systems AB
|
12583
|
+
* Released under LGPL License.
|
12584
|
+
*
|
12585
|
+
* License: http://www.tinymce.com/license
|
12586
|
+
* Contributing: http://www.tinymce.com/contributing
|
12587
|
+
*/
|
12588
|
+
|
12589
|
+
/**
|
12590
|
+
* RangeUtils
|
12591
|
+
*
|
12592
|
+
* @class tinymce.dom.RangeUtils
|
12593
|
+
* @private
|
12594
|
+
*/
|
12595
|
+
define("tinymce/dom/RangeUtils", [
|
12596
|
+
"tinymce/util/Tools",
|
12597
|
+
"tinymce/dom/TreeWalker"
|
12598
|
+
], function(Tools, TreeWalker) {
|
12599
|
+
var each = Tools.each;
|
12600
|
+
|
12601
|
+
function RangeUtils(dom) {
|
12602
|
+
/**
|
12603
|
+
* Walks the specified range like object and executes the callback for each sibling collection it finds.
|
12604
|
+
*
|
12605
|
+
* @method walk
|
12606
|
+
* @param {Object} rng Range like object.
|
12607
|
+
* @param {function} callback Callback function to execute for each sibling collection.
|
12608
|
+
*/
|
12609
|
+
this.walk = function(rng, callback) {
|
12610
|
+
var startContainer = rng.startContainer,
|
12611
|
+
startOffset = rng.startOffset,
|
12612
|
+
endContainer = rng.endContainer,
|
12613
|
+
endOffset = rng.endOffset,
|
12614
|
+
ancestor, startPoint,
|
12615
|
+
endPoint, node, parent, siblings, nodes;
|
12616
|
+
|
12617
|
+
// Handle table cell selection the table plugin enables
|
12618
|
+
// you to fake select table cells and perform formatting actions on them
|
12619
|
+
nodes = dom.select('td.mce-item-selected,th.mce-item-selected');
|
12620
|
+
if (nodes.length > 0) {
|
12621
|
+
each(nodes, function(node) {
|
12622
|
+
callback([node]);
|
12623
|
+
});
|
12624
|
+
|
12625
|
+
return;
|
12626
|
+
}
|
12627
|
+
|
12628
|
+
/**
|
12629
|
+
* Excludes start/end text node if they are out side the range
|
12630
|
+
*
|
12631
|
+
* @private
|
12632
|
+
* @param {Array} nodes Nodes to exclude items from.
|
12633
|
+
* @return {Array} Array with nodes excluding the start/end container if needed.
|
12634
|
+
*/
|
12635
|
+
function exclude(nodes) {
|
12636
|
+
var node;
|
12637
|
+
|
12638
|
+
// First node is excluded
|
12639
|
+
node = nodes[0];
|
12640
|
+
if (node.nodeType === 3 && node === startContainer && startOffset >= node.nodeValue.length) {
|
12641
|
+
nodes.splice(0, 1);
|
12642
|
+
}
|
12643
|
+
|
12644
|
+
// Last node is excluded
|
12645
|
+
node = nodes[nodes.length - 1];
|
12646
|
+
if (endOffset === 0 && nodes.length > 0 && node === endContainer && node.nodeType === 3) {
|
12647
|
+
nodes.splice(nodes.length - 1, 1);
|
12648
|
+
}
|
12649
|
+
|
12650
|
+
return nodes;
|
12651
|
+
}
|
12652
|
+
|
12653
|
+
/**
|
12654
|
+
* Collects siblings
|
12655
|
+
*
|
12656
|
+
* @private
|
12657
|
+
* @param {Node} node Node to collect siblings from.
|
12658
|
+
* @param {String} name Name of the sibling to check for.
|
12659
|
+
* @return {Array} Array of collected siblings.
|
12660
|
+
*/
|
12661
|
+
function collectSiblings(node, name, end_node) {
|
12662
|
+
var siblings = [];
|
12663
|
+
|
12664
|
+
for (; node && node != end_node; node = node[name]) {
|
12665
|
+
siblings.push(node);
|
12666
|
+
}
|
12667
|
+
|
12668
|
+
return siblings;
|
12669
|
+
}
|
12670
|
+
|
12671
|
+
/**
|
12672
|
+
* Find an end point this is the node just before the common ancestor root.
|
12673
|
+
*
|
12674
|
+
* @private
|
12675
|
+
* @param {Node} node Node to start at.
|
12676
|
+
* @param {Node} root Root/ancestor element to stop just before.
|
12677
|
+
* @return {Node} Node just before the root element.
|
12678
|
+
*/
|
12679
|
+
function findEndPoint(node, root) {
|
12680
|
+
do {
|
12681
|
+
if (node.parentNode == root) {
|
12682
|
+
return node;
|
12683
|
+
}
|
12684
|
+
|
12685
|
+
node = node.parentNode;
|
12686
|
+
} while(node);
|
12687
|
+
}
|
12688
|
+
|
12689
|
+
function walkBoundary(start_node, end_node, next) {
|
12690
|
+
var siblingName = next ? 'nextSibling' : 'previousSibling';
|
12691
|
+
|
12692
|
+
for (node = start_node, parent = node.parentNode; node && node != end_node; node = parent) {
|
12693
|
+
parent = node.parentNode;
|
12694
|
+
siblings = collectSiblings(node == start_node ? node : node[siblingName], siblingName);
|
12695
|
+
|
12696
|
+
if (siblings.length) {
|
12697
|
+
if (!next) {
|
12698
|
+
siblings.reverse();
|
12699
|
+
}
|
12700
|
+
|
12701
|
+
callback(exclude(siblings));
|
12702
|
+
}
|
12703
|
+
}
|
12704
|
+
}
|
12705
|
+
|
12706
|
+
// If index based start position then resolve it
|
12707
|
+
if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) {
|
12708
|
+
startContainer = startContainer.childNodes[startOffset];
|
12709
|
+
}
|
12710
|
+
|
12711
|
+
// If index based end position then resolve it
|
12712
|
+
if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) {
|
12713
|
+
endContainer = endContainer.childNodes[Math.min(endOffset - 1, endContainer.childNodes.length - 1)];
|
12714
|
+
}
|
12715
|
+
|
12716
|
+
// Same container
|
12717
|
+
if (startContainer == endContainer) {
|
12718
|
+
return callback(exclude([startContainer]));
|
12719
|
+
}
|
12720
|
+
|
12721
|
+
// Find common ancestor and end points
|
12722
|
+
ancestor = dom.findCommonAncestor(startContainer, endContainer);
|
12723
|
+
|
12724
|
+
// Process left side
|
12725
|
+
for (node = startContainer; node; node = node.parentNode) {
|
12726
|
+
if (node === endContainer) {
|
12727
|
+
return walkBoundary(startContainer, ancestor, true);
|
12728
|
+
}
|
12729
|
+
|
12730
|
+
if (node === ancestor) {
|
12731
|
+
break;
|
12732
|
+
}
|
12733
|
+
}
|
12734
|
+
|
12735
|
+
// Process right side
|
12736
|
+
for (node = endContainer; node; node = node.parentNode) {
|
12737
|
+
if (node === startContainer) {
|
12738
|
+
return walkBoundary(endContainer, ancestor);
|
12739
|
+
}
|
12740
|
+
|
12741
|
+
if (node === ancestor) {
|
12742
|
+
break;
|
12743
|
+
}
|
12744
|
+
}
|
12745
|
+
|
12746
|
+
// Find start/end point
|
12747
|
+
startPoint = findEndPoint(startContainer, ancestor) || startContainer;
|
12748
|
+
endPoint = findEndPoint(endContainer, ancestor) || endContainer;
|
12749
|
+
|
12750
|
+
// Walk left leaf
|
12751
|
+
walkBoundary(startContainer, startPoint, true);
|
12752
|
+
|
12753
|
+
// Walk the middle from start to end point
|
12754
|
+
siblings = collectSiblings(
|
12755
|
+
startPoint == startContainer ? startPoint : startPoint.nextSibling,
|
12756
|
+
'nextSibling',
|
12757
|
+
endPoint == endContainer ? endPoint.nextSibling : endPoint
|
12758
|
+
);
|
12759
|
+
|
12760
|
+
if (siblings.length) {
|
12761
|
+
callback(exclude(siblings));
|
12762
|
+
}
|
12763
|
+
|
12764
|
+
// Walk right leaf
|
12765
|
+
walkBoundary(endContainer, endPoint);
|
12766
|
+
};
|
12767
|
+
|
12768
|
+
/**
|
12769
|
+
* Splits the specified range at it's start/end points.
|
12770
|
+
*
|
12771
|
+
* @private
|
12772
|
+
* @param {Range/RangeObject} rng Range to split.
|
12773
|
+
* @return {Object} Range position object.
|
12774
|
+
*/
|
12775
|
+
this.split = function(rng) {
|
12776
|
+
var startContainer = rng.startContainer,
|
12777
|
+
startOffset = rng.startOffset,
|
12778
|
+
endContainer = rng.endContainer,
|
12779
|
+
endOffset = rng.endOffset;
|
12780
|
+
|
12781
|
+
function splitText(node, offset) {
|
12782
|
+
return node.splitText(offset);
|
12783
|
+
}
|
12784
|
+
|
12785
|
+
// Handle single text node
|
12786
|
+
if (startContainer == endContainer && startContainer.nodeType == 3) {
|
12787
|
+
if (startOffset > 0 && startOffset < startContainer.nodeValue.length) {
|
12788
|
+
endContainer = splitText(startContainer, startOffset);
|
12789
|
+
startContainer = endContainer.previousSibling;
|
12790
|
+
|
12791
|
+
if (endOffset > startOffset) {
|
12792
|
+
endOffset = endOffset - startOffset;
|
12793
|
+
startContainer = endContainer = splitText(endContainer, endOffset).previousSibling;
|
12794
|
+
endOffset = endContainer.nodeValue.length;
|
12795
|
+
startOffset = 0;
|
12796
|
+
} else {
|
12797
|
+
endOffset = 0;
|
12798
|
+
}
|
12799
|
+
}
|
12800
|
+
} else {
|
12801
|
+
// Split startContainer text node if needed
|
12802
|
+
if (startContainer.nodeType == 3 && startOffset > 0 && startOffset < startContainer.nodeValue.length) {
|
12803
|
+
startContainer = splitText(startContainer, startOffset);
|
12804
|
+
startOffset = 0;
|
12805
|
+
}
|
12806
|
+
|
12807
|
+
// Split endContainer text node if needed
|
12808
|
+
if (endContainer.nodeType == 3 && endOffset > 0 && endOffset < endContainer.nodeValue.length) {
|
12809
|
+
endContainer = splitText(endContainer, endOffset).previousSibling;
|
12810
|
+
endOffset = endContainer.nodeValue.length;
|
12811
|
+
}
|
12812
|
+
}
|
12813
|
+
|
12814
|
+
return {
|
12815
|
+
startContainer: startContainer,
|
12816
|
+
startOffset: startOffset,
|
12817
|
+
endContainer: endContainer,
|
12818
|
+
endOffset: endOffset
|
12819
|
+
};
|
12820
|
+
};
|
12821
|
+
|
12822
|
+
/**
|
12823
|
+
* Normalizes the specified range by finding the closest best suitable caret location.
|
12824
|
+
*
|
12825
|
+
* @private
|
12826
|
+
* @param {Range} rng Range to normalize.
|
12827
|
+
* @return {Boolean} True/false if the specified range was normalized or not.
|
12828
|
+
*/
|
12829
|
+
this.normalize = function(rng) {
|
12830
|
+
var normalized, collapsed;
|
12831
|
+
|
12832
|
+
function normalizeEndPoint(start) {
|
12833
|
+
var container, offset, walker, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
|
12834
|
+
var directionLeft, isAfterNode;
|
12835
|
+
|
12836
|
+
function hasBrBeforeAfter(node, left) {
|
12837
|
+
var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
|
12838
|
+
|
12839
|
+
while ((node = walker[left ? 'prev' : 'next']())) {
|
12840
|
+
if (node.nodeName === "BR") {
|
12841
|
+
return true;
|
12842
|
+
}
|
12843
|
+
}
|
12844
|
+
}
|
12845
|
+
|
12846
|
+
function isPrevNode(node, name) {
|
12847
|
+
return node.previousSibling && node.previousSibling.nodeName == name;
|
12848
|
+
}
|
12849
|
+
|
12850
|
+
// Walks the dom left/right to find a suitable text node to move the endpoint into
|
12851
|
+
// It will only walk within the current parent block or body and will stop if it hits a block or a BR/IMG
|
12852
|
+
function findTextNodeRelative(left, startNode) {
|
12853
|
+
var walker, lastInlineElement, parentBlockContainer;
|
12854
|
+
|
12855
|
+
startNode = startNode || container;
|
12856
|
+
parentBlockContainer = dom.getParent(startNode.parentNode, dom.isBlock) || body;
|
12857
|
+
|
12858
|
+
// Lean left before the BR element if it's the only BR within a block element. Gecko bug: #6680
|
12859
|
+
// This: <p><br>|</p> becomes <p>|<br></p>
|
12860
|
+
if (left && startNode.nodeName == 'BR' && isAfterNode && dom.isEmpty(parentBlockContainer)) {
|
12861
|
+
container = startNode.parentNode;
|
12862
|
+
offset = dom.nodeIndex(startNode);
|
12863
|
+
normalized = true;
|
12864
|
+
return;
|
12865
|
+
}
|
12866
|
+
|
12867
|
+
// Walk left until we hit a text node we can move to or a block/br/img
|
12868
|
+
walker = new TreeWalker(startNode, parentBlockContainer);
|
12869
|
+
while ((node = walker[left ? 'prev' : 'next']())) {
|
12870
|
+
// Found text node that has a length
|
12871
|
+
if (node.nodeType === 3 && node.nodeValue.length > 0) {
|
12872
|
+
container = node;
|
12873
|
+
offset = left ? node.nodeValue.length : 0;
|
12874
|
+
normalized = true;
|
12875
|
+
return;
|
12876
|
+
}
|
12877
|
+
|
12878
|
+
// Break if we find a block or a BR/IMG/INPUT etc
|
12879
|
+
if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
12880
|
+
return;
|
12881
|
+
}
|
12882
|
+
|
12883
|
+
lastInlineElement = node;
|
12884
|
+
}
|
12885
|
+
|
12886
|
+
// Only fetch the last inline element when in caret mode for now
|
12887
|
+
if (collapsed && lastInlineElement) {
|
12888
|
+
container = lastInlineElement;
|
12889
|
+
normalized = true;
|
12890
|
+
offset = 0;
|
12891
|
+
}
|
12892
|
+
}
|
12893
|
+
|
12894
|
+
container = rng[(start ? 'start' : 'end') + 'Container'];
|
12895
|
+
offset = rng[(start ? 'start' : 'end') + 'Offset'];
|
12896
|
+
isAfterNode = container.nodeType == 1 && offset === container.childNodes.length;
|
12897
|
+
nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
12898
|
+
directionLeft = start;
|
12899
|
+
|
12900
|
+
if (container.nodeType == 1 && offset > container.childNodes.length - 1) {
|
12901
|
+
directionLeft = false;
|
12902
|
+
}
|
12903
|
+
|
12904
|
+
// If the container is a document move it to the body element
|
12905
|
+
if (container.nodeType === 9) {
|
12906
|
+
container = dom.getRoot();
|
12907
|
+
offset = 0;
|
12908
|
+
}
|
12909
|
+
|
12910
|
+
// If the container is body try move it into the closest text node or position
|
12911
|
+
if (container === body) {
|
12912
|
+
// If start is before/after a image, table etc
|
12913
|
+
if (directionLeft) {
|
12914
|
+
node = container.childNodes[offset > 0 ? offset - 1 : 0];
|
12915
|
+
if (node) {
|
12916
|
+
nodeName = node.nodeName.toLowerCase();
|
12917
|
+
if (nonEmptyElementsMap[node.nodeName] || node.nodeName == "TABLE") {
|
12918
|
+
return;
|
12919
|
+
}
|
12920
|
+
}
|
12921
|
+
}
|
12922
|
+
|
12923
|
+
// Resolve the index
|
12924
|
+
if (container.hasChildNodes()) {
|
12925
|
+
offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
|
12926
|
+
container = container.childNodes[offset];
|
12927
|
+
offset = 0;
|
12928
|
+
|
12929
|
+
// Don't walk into elements that doesn't have any child nodes like a IMG
|
12930
|
+
if (container.hasChildNodes() && !/TABLE/.test(container.nodeName)) {
|
12931
|
+
// Walk the DOM to find a text node to place the caret at or a BR
|
12932
|
+
node = container;
|
12933
|
+
walker = new TreeWalker(container, body);
|
12934
|
+
|
12935
|
+
do {
|
12936
|
+
// Found a text node use that position
|
12937
|
+
if (node.nodeType === 3 && node.nodeValue.length > 0) {
|
12938
|
+
offset = directionLeft ? 0 : node.nodeValue.length;
|
12939
|
+
container = node;
|
12940
|
+
normalized = true;
|
12941
|
+
break;
|
12942
|
+
}
|
12943
|
+
|
12944
|
+
// Found a BR/IMG element that we can place the caret before
|
12945
|
+
if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
12946
|
+
offset = dom.nodeIndex(node);
|
12947
|
+
container = node.parentNode;
|
12948
|
+
|
12949
|
+
// Put caret after image when moving the end point
|
12950
|
+
if (node.nodeName == "IMG" && !directionLeft) {
|
12951
|
+
offset++;
|
12952
|
+
}
|
12953
|
+
|
12954
|
+
normalized = true;
|
12955
|
+
break;
|
12956
|
+
}
|
12957
|
+
} while ((node = (directionLeft ? walker.next() : walker.prev())));
|
12958
|
+
}
|
12959
|
+
}
|
12960
|
+
}
|
12961
|
+
|
12962
|
+
// Lean the caret to the left if possible
|
12963
|
+
if (collapsed) {
|
12964
|
+
// So this: <b>x</b><i>|x</i>
|
12965
|
+
// Becomes: <b>x|</b><i>x</i>
|
12966
|
+
// Seems that only gecko has issues with this
|
12967
|
+
if (container.nodeType === 3 && offset === 0) {
|
12968
|
+
findTextNodeRelative(true);
|
12969
|
+
}
|
12970
|
+
|
12971
|
+
// Lean left into empty inline elements when the caret is before a BR
|
12972
|
+
// So this: <i><b></b><i>|<br></i>
|
12973
|
+
// Becomes: <i><b>|</b><i><br></i>
|
12974
|
+
// Seems that only gecko has issues with this.
|
12975
|
+
// Special edge case for <p><a>x</a>|<br></p> since we don't want <p><a>x|</a><br></p>
|
12976
|
+
if (container.nodeType === 1) {
|
12977
|
+
node = container.childNodes[offset];
|
12978
|
+
|
12979
|
+
// Offset is after the containers last child
|
12980
|
+
// then use the previous child for normalization
|
12981
|
+
if (!node) {
|
12982
|
+
node = container.childNodes[offset - 1];
|
12983
|
+
}
|
12984
|
+
|
12985
|
+
if (node && node.nodeName === 'BR' && !isPrevNode(node, 'A') &&
|
12986
|
+
!hasBrBeforeAfter(node) && !hasBrBeforeAfter(node, true)) {
|
12987
|
+
findTextNodeRelative(true, node);
|
12988
|
+
}
|
12989
|
+
}
|
12990
|
+
}
|
12991
|
+
|
12992
|
+
// Lean the start of the selection right if possible
|
12993
|
+
// So this: x[<b>x]</b>
|
12994
|
+
// Becomes: x<b>[x]</b>
|
12995
|
+
if (directionLeft && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
|
12996
|
+
findTextNodeRelative(false);
|
12997
|
+
}
|
12998
|
+
|
12999
|
+
// Set endpoint if it was normalized
|
13000
|
+
if (normalized) {
|
13001
|
+
rng['set' + (start ? 'Start' : 'End')](container, offset);
|
13002
|
+
}
|
13003
|
+
}
|
13004
|
+
|
13005
|
+
collapsed = rng.collapsed;
|
13006
|
+
|
13007
|
+
normalizeEndPoint(true);
|
13008
|
+
|
13009
|
+
if (!collapsed) {
|
13010
|
+
normalizeEndPoint();
|
13011
|
+
}
|
13012
|
+
|
13013
|
+
// If it was collapsed then make sure it still is
|
13014
|
+
if (normalized && collapsed) {
|
13015
|
+
rng.collapse(true);
|
13016
|
+
}
|
13017
|
+
|
13018
|
+
return normalized;
|
13019
|
+
};
|
13020
|
+
}
|
13021
|
+
|
13022
|
+
/**
|
13023
|
+
* Compares two ranges and checks if they are equal.
|
13024
|
+
*
|
13025
|
+
* @static
|
13026
|
+
* @method compareRanges
|
13027
|
+
* @param {DOMRange} rng1 First range to compare.
|
13028
|
+
* @param {DOMRange} rng2 First range to compare.
|
13029
|
+
* @return {Boolean} true/false if the ranges are equal.
|
13030
|
+
*/
|
13031
|
+
RangeUtils.compareRanges = function(rng1, rng2) {
|
13032
|
+
if (rng1 && rng2) {
|
13033
|
+
// Compare native IE ranges
|
13034
|
+
if (rng1.item || rng1.duplicate) {
|
13035
|
+
// Both are control ranges and the selected element matches
|
13036
|
+
if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0)) {
|
13037
|
+
return true;
|
13038
|
+
}
|
13039
|
+
|
13040
|
+
// Both are text ranges and the range matches
|
13041
|
+
if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1)) {
|
13042
|
+
return true;
|
13043
|
+
}
|
13044
|
+
} else {
|
13045
|
+
// Compare w3c ranges
|
13046
|
+
return rng1.startContainer == rng2.startContainer && rng1.startOffset == rng2.startOffset;
|
13047
|
+
}
|
13048
|
+
}
|
13049
|
+
|
13050
|
+
return false;
|
13051
|
+
};
|
13052
|
+
|
13053
|
+
return RangeUtils;
|
13054
|
+
});
|
13055
|
+
|
12571
13056
|
// Included from: js/tinymce/classes/dom/Selection.js
|
12572
13057
|
|
12573
13058
|
/**
|
@@ -12593,9 +13078,10 @@ define("tinymce/dom/Selection", [
|
|
12593
13078
|
"tinymce/dom/TreeWalker",
|
12594
13079
|
"tinymce/dom/TridentSelection",
|
12595
13080
|
"tinymce/dom/ControlSelection",
|
13081
|
+
"tinymce/dom/RangeUtils",
|
12596
13082
|
"tinymce/Env",
|
12597
13083
|
"tinymce/util/Tools"
|
12598
|
-
], function(TreeWalker, TridentSelection, ControlSelection, Env, Tools) {
|
13084
|
+
], function(TreeWalker, TridentSelection, ControlSelection, RangeUtils, Env, Tools) {
|
12599
13085
|
var each = Tools.each, grep = Tools.grep, trim = Tools.trim;
|
12600
13086
|
var isIE = Env.ie, isOpera = Env.opera;
|
12601
13087
|
|
@@ -13345,6 +13831,19 @@ define("tinymce/dom/Selection", [
|
|
13345
13831
|
getRng: function(w3c) {
|
13346
13832
|
var self = this, selection, rng, elm, doc = self.win.document, ieRng;
|
13347
13833
|
|
13834
|
+
function tryCompareBounderyPoints(how, sourceRange, destinationRange) {
|
13835
|
+
try {
|
13836
|
+
return sourceRange.compareBoundaryPoints(how, destinationRange);
|
13837
|
+
} catch (ex) {
|
13838
|
+
// Gecko throws wrong document exception if the range points
|
13839
|
+
// to nodes that where removed from the dom #6690
|
13840
|
+
// Browsers should mutate existing DOMRange instances so that they always point
|
13841
|
+
// to something in the document this is not the case in Gecko works fine in IE/WebKit/Blink
|
13842
|
+
// For performance reasons just return -1
|
13843
|
+
return -1;
|
13844
|
+
}
|
13845
|
+
}
|
13846
|
+
|
13348
13847
|
// Use last rng passed from FocusManager if it's available this enables
|
13349
13848
|
// calls to editor.selection.getStart() to work when caret focus is lost on IE
|
13350
13849
|
if (!w3c && self.lastFocusBookmark) {
|
@@ -13412,8 +13911,8 @@ define("tinymce/dom/Selection", [
|
|
13412
13911
|
}
|
13413
13912
|
|
13414
13913
|
if (self.selectedRange && self.explicitRange) {
|
13415
|
-
if (
|
13416
|
-
|
13914
|
+
if (tryCompareBounderyPoints(rng.START_TO_START, rng, self.selectedRange) === 0 &&
|
13915
|
+
tryCompareBounderyPoints(rng.END_TO_END, rng, self.selectedRange) === 0) {
|
13417
13916
|
// Safari, Opera and Chrome only ever select text which causes the range to change.
|
13418
13917
|
// This lets us use the originally set range if the selection hasn't been changed by the user.
|
13419
13918
|
rng = self.explicitRange;
|
@@ -13612,7 +14111,7 @@ define("tinymce/dom/Selection", [
|
|
13612
14111
|
return selectedBlocks;
|
13613
14112
|
},
|
13614
14113
|
|
13615
|
-
isForward: function(){
|
14114
|
+
isForward: function() {
|
13616
14115
|
var dom = this.dom, sel = this.getSel(), anchorRange, focusRange;
|
13617
14116
|
|
13618
14117
|
// No support for selection direction then always return true
|
@@ -13632,188 +14131,13 @@ define("tinymce/dom/Selection", [
|
|
13632
14131
|
},
|
13633
14132
|
|
13634
14133
|
normalize: function() {
|
13635
|
-
var self = this, rng
|
13636
|
-
|
13637
|
-
function normalizeEndPoint(start) {
|
13638
|
-
var container, offset, walker, dom = self.dom, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
|
13639
|
-
var directionLeft;
|
13640
|
-
|
13641
|
-
function hasBrBeforeAfter(node, left) {
|
13642
|
-
var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
|
13643
|
-
|
13644
|
-
while ((node = walker[left ? 'prev' : 'next']())) {
|
13645
|
-
if (node.nodeName === "BR") {
|
13646
|
-
return true;
|
13647
|
-
}
|
13648
|
-
}
|
13649
|
-
}
|
13650
|
-
|
13651
|
-
function isPrevNode(node, name) {
|
13652
|
-
return node.previousSibling && node.previousSibling.nodeName == name;
|
13653
|
-
}
|
13654
|
-
|
13655
|
-
// Walks the dom left/right to find a suitable text node to move the endpoint into
|
13656
|
-
// It will only walk within the current parent block or body and will stop if it hits a block or a BR/IMG
|
13657
|
-
function findTextNodeRelative(left, startNode) {
|
13658
|
-
var walker, lastInlineElement;
|
13659
|
-
|
13660
|
-
startNode = startNode || container;
|
13661
|
-
walker = new TreeWalker(startNode, dom.getParent(startNode.parentNode, dom.isBlock) || body);
|
13662
|
-
|
13663
|
-
// Walk left until we hit a text node we can move to or a block/br/img
|
13664
|
-
while ((node = walker[left ? 'prev' : 'next']())) {
|
13665
|
-
// Found text node that has a length
|
13666
|
-
if (node.nodeType === 3 && node.nodeValue.length > 0) {
|
13667
|
-
container = node;
|
13668
|
-
offset = left ? node.nodeValue.length : 0;
|
13669
|
-
normalized = true;
|
13670
|
-
return;
|
13671
|
-
}
|
13672
|
-
|
13673
|
-
// Break if we find a block or a BR/IMG/INPUT etc
|
13674
|
-
if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
13675
|
-
return;
|
13676
|
-
}
|
13677
|
-
|
13678
|
-
lastInlineElement = node;
|
13679
|
-
}
|
14134
|
+
var self = this, rng = self.getRng();
|
13680
14135
|
|
13681
|
-
|
13682
|
-
if (collapsed && lastInlineElement) {
|
13683
|
-
container = lastInlineElement;
|
13684
|
-
normalized = true;
|
13685
|
-
offset = 0;
|
13686
|
-
}
|
13687
|
-
}
|
13688
|
-
|
13689
|
-
container = rng[(start ? 'start' : 'end') + 'Container'];
|
13690
|
-
offset = rng[(start ? 'start' : 'end') + 'Offset'];
|
13691
|
-
nonEmptyElementsMap = dom.schema.getNonEmptyElements();
|
13692
|
-
directionLeft = start;
|
13693
|
-
|
13694
|
-
if (container.nodeType == 1 && offset > container.childNodes.length - 1) {
|
13695
|
-
directionLeft = false;
|
13696
|
-
}
|
13697
|
-
|
13698
|
-
// If the container is a document move it to the body element
|
13699
|
-
if (container.nodeType === 9) {
|
13700
|
-
container = dom.getRoot();
|
13701
|
-
offset = 0;
|
13702
|
-
}
|
13703
|
-
|
13704
|
-
// If the container is body try move it into the closest text node or position
|
13705
|
-
if (container === body) {
|
13706
|
-
// If start is before/after a image, table etc
|
13707
|
-
if (directionLeft) {
|
13708
|
-
node = container.childNodes[offset > 0 ? offset - 1 : 0];
|
13709
|
-
if (node) {
|
13710
|
-
nodeName = node.nodeName.toLowerCase();
|
13711
|
-
if (nonEmptyElementsMap[node.nodeName] || node.nodeName == "TABLE") {
|
13712
|
-
return;
|
13713
|
-
}
|
13714
|
-
}
|
13715
|
-
}
|
13716
|
-
|
13717
|
-
// Resolve the index
|
13718
|
-
if (container.hasChildNodes()) {
|
13719
|
-
offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
|
13720
|
-
container = container.childNodes[offset];
|
13721
|
-
offset = 0;
|
13722
|
-
|
13723
|
-
// Don't walk into elements that doesn't have any child nodes like a IMG
|
13724
|
-
if (container.hasChildNodes() && !/TABLE/.test(container.nodeName)) {
|
13725
|
-
// Walk the DOM to find a text node to place the caret at or a BR
|
13726
|
-
node = container;
|
13727
|
-
walker = new TreeWalker(container, body);
|
13728
|
-
|
13729
|
-
do {
|
13730
|
-
// Found a text node use that position
|
13731
|
-
if (node.nodeType === 3 && node.nodeValue.length > 0) {
|
13732
|
-
offset = directionLeft ? 0 : node.nodeValue.length;
|
13733
|
-
container = node;
|
13734
|
-
normalized = true;
|
13735
|
-
break;
|
13736
|
-
}
|
13737
|
-
|
13738
|
-
// Found a BR/IMG element that we can place the caret before
|
13739
|
-
if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
|
13740
|
-
offset = dom.nodeIndex(node);
|
13741
|
-
container = node.parentNode;
|
13742
|
-
|
13743
|
-
// Put caret after image when moving the end point
|
13744
|
-
if (node.nodeName == "IMG" && !directionLeft) {
|
13745
|
-
offset++;
|
13746
|
-
}
|
13747
|
-
|
13748
|
-
normalized = true;
|
13749
|
-
break;
|
13750
|
-
}
|
13751
|
-
} while ((node = (directionLeft ? walker.next() : walker.prev())));
|
13752
|
-
}
|
13753
|
-
}
|
13754
|
-
}
|
13755
|
-
|
13756
|
-
// Lean the caret to the left if possible
|
13757
|
-
if (collapsed) {
|
13758
|
-
// So this: <b>x</b><i>|x</i>
|
13759
|
-
// Becomes: <b>x|</b><i>x</i>
|
13760
|
-
// Seems that only gecko has issues with this
|
13761
|
-
if (container.nodeType === 3 && offset === 0) {
|
13762
|
-
findTextNodeRelative(true);
|
13763
|
-
}
|
13764
|
-
|
13765
|
-
// Lean left into empty inline elements when the caret is before a BR
|
13766
|
-
// So this: <i><b></b><i>|<br></i>
|
13767
|
-
// Becomes: <i><b>|</b><i><br></i>
|
13768
|
-
// Seems that only gecko has issues with this.
|
13769
|
-
// Special edge case for <p><a>x</a>|<br></p> since we don't want <p><a>x|</a><br></p>
|
13770
|
-
if (container.nodeType === 1) {
|
13771
|
-
node = container.childNodes[offset];
|
13772
|
-
if(node && node.nodeName === 'BR' && !isPrevNode(node, 'A') &&
|
13773
|
-
!hasBrBeforeAfter(node) && !hasBrBeforeAfter(node, true)) {
|
13774
|
-
findTextNodeRelative(true, container.childNodes[offset]);
|
13775
|
-
}
|
13776
|
-
}
|
13777
|
-
}
|
13778
|
-
|
13779
|
-
// Lean the start of the selection right if possible
|
13780
|
-
// So this: x[<b>x]</b>
|
13781
|
-
// Becomes: x<b>[x]</b>
|
13782
|
-
if (directionLeft && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
|
13783
|
-
findTextNodeRelative(false);
|
13784
|
-
}
|
13785
|
-
|
13786
|
-
// Set endpoint if it was normalized
|
13787
|
-
if (normalized) {
|
13788
|
-
rng['set' + (start ? 'Start' : 'End')](container, offset);
|
13789
|
-
}
|
13790
|
-
}
|
13791
|
-
|
13792
|
-
// Normalize only on non IE browsers for now
|
13793
|
-
if (isIE) {
|
13794
|
-
return;
|
13795
|
-
}
|
13796
|
-
|
13797
|
-
rng = self.getRng();
|
13798
|
-
collapsed = rng.collapsed;
|
13799
|
-
|
13800
|
-
// Normalize the end points
|
13801
|
-
normalizeEndPoint(true);
|
13802
|
-
|
13803
|
-
if (!collapsed) {
|
13804
|
-
normalizeEndPoint();
|
13805
|
-
}
|
13806
|
-
|
13807
|
-
// Set the selection if it was normalized
|
13808
|
-
if (normalized) {
|
13809
|
-
// If it was collapsed then make sure it still is
|
13810
|
-
if (collapsed) {
|
13811
|
-
rng.collapse(true);
|
13812
|
-
}
|
13813
|
-
|
13814
|
-
//console.log(self.dom.dumpRng(rng));
|
14136
|
+
if (!isIE && new RangeUtils(self.dom).normalize(rng)) {
|
13815
14137
|
self.setRng(rng, self.isForward());
|
13816
14138
|
}
|
14139
|
+
|
14140
|
+
return rng;
|
13817
14141
|
},
|
13818
14142
|
|
13819
14143
|
/**
|
@@ -13991,285 +14315,6 @@ define("tinymce/dom/Selection", [
|
|
13991
14315
|
return Selection;
|
13992
14316
|
});
|
13993
14317
|
|
13994
|
-
// Included from: js/tinymce/classes/dom/RangeUtils.js
|
13995
|
-
|
13996
|
-
/**
|
13997
|
-
* Range.js
|
13998
|
-
*
|
13999
|
-
* Copyright, Moxiecode Systems AB
|
14000
|
-
* Released under LGPL License.
|
14001
|
-
*
|
14002
|
-
* License: http://www.tinymce.com/license
|
14003
|
-
* Contributing: http://www.tinymce.com/contributing
|
14004
|
-
*/
|
14005
|
-
|
14006
|
-
/**
|
14007
|
-
* RangeUtils
|
14008
|
-
*
|
14009
|
-
* @class tinymce.dom.RangeUtils
|
14010
|
-
* @private
|
14011
|
-
*/
|
14012
|
-
define("tinymce/dom/RangeUtils", [
|
14013
|
-
"tinymce/util/Tools"
|
14014
|
-
], function(Tools) {
|
14015
|
-
var each = Tools.each;
|
14016
|
-
|
14017
|
-
function RangeUtils(dom) {
|
14018
|
-
/**
|
14019
|
-
* Walks the specified range like object and executes the callback for each sibling collection it finds.
|
14020
|
-
*
|
14021
|
-
* @method walk
|
14022
|
-
* @param {Object} rng Range like object.
|
14023
|
-
* @param {function} callback Callback function to execute for each sibling collection.
|
14024
|
-
*/
|
14025
|
-
this.walk = function(rng, callback) {
|
14026
|
-
var startContainer = rng.startContainer,
|
14027
|
-
startOffset = rng.startOffset,
|
14028
|
-
endContainer = rng.endContainer,
|
14029
|
-
endOffset = rng.endOffset,
|
14030
|
-
ancestor, startPoint,
|
14031
|
-
endPoint, node, parent, siblings, nodes;
|
14032
|
-
|
14033
|
-
// Handle table cell selection the table plugin enables
|
14034
|
-
// you to fake select table cells and perform formatting actions on them
|
14035
|
-
nodes = dom.select('td.mce-item-selected,th.mce-item-selected');
|
14036
|
-
if (nodes.length > 0) {
|
14037
|
-
each(nodes, function(node) {
|
14038
|
-
callback([node]);
|
14039
|
-
});
|
14040
|
-
|
14041
|
-
return;
|
14042
|
-
}
|
14043
|
-
|
14044
|
-
/**
|
14045
|
-
* Excludes start/end text node if they are out side the range
|
14046
|
-
*
|
14047
|
-
* @private
|
14048
|
-
* @param {Array} nodes Nodes to exclude items from.
|
14049
|
-
* @return {Array} Array with nodes excluding the start/end container if needed.
|
14050
|
-
*/
|
14051
|
-
function exclude(nodes) {
|
14052
|
-
var node;
|
14053
|
-
|
14054
|
-
// First node is excluded
|
14055
|
-
node = nodes[0];
|
14056
|
-
if (node.nodeType === 3 && node === startContainer && startOffset >= node.nodeValue.length) {
|
14057
|
-
nodes.splice(0, 1);
|
14058
|
-
}
|
14059
|
-
|
14060
|
-
// Last node is excluded
|
14061
|
-
node = nodes[nodes.length - 1];
|
14062
|
-
if (endOffset === 0 && nodes.length > 0 && node === endContainer && node.nodeType === 3) {
|
14063
|
-
nodes.splice(nodes.length - 1, 1);
|
14064
|
-
}
|
14065
|
-
|
14066
|
-
return nodes;
|
14067
|
-
}
|
14068
|
-
|
14069
|
-
/**
|
14070
|
-
* Collects siblings
|
14071
|
-
*
|
14072
|
-
* @private
|
14073
|
-
* @param {Node} node Node to collect siblings from.
|
14074
|
-
* @param {String} name Name of the sibling to check for.
|
14075
|
-
* @return {Array} Array of collected siblings.
|
14076
|
-
*/
|
14077
|
-
function collectSiblings(node, name, end_node) {
|
14078
|
-
var siblings = [];
|
14079
|
-
|
14080
|
-
for (; node && node != end_node; node = node[name]) {
|
14081
|
-
siblings.push(node);
|
14082
|
-
}
|
14083
|
-
|
14084
|
-
return siblings;
|
14085
|
-
}
|
14086
|
-
|
14087
|
-
/**
|
14088
|
-
* Find an end point this is the node just before the common ancestor root.
|
14089
|
-
*
|
14090
|
-
* @private
|
14091
|
-
* @param {Node} node Node to start at.
|
14092
|
-
* @param {Node} root Root/ancestor element to stop just before.
|
14093
|
-
* @return {Node} Node just before the root element.
|
14094
|
-
*/
|
14095
|
-
function findEndPoint(node, root) {
|
14096
|
-
do {
|
14097
|
-
if (node.parentNode == root) {
|
14098
|
-
return node;
|
14099
|
-
}
|
14100
|
-
|
14101
|
-
node = node.parentNode;
|
14102
|
-
} while(node);
|
14103
|
-
}
|
14104
|
-
|
14105
|
-
function walkBoundary(start_node, end_node, next) {
|
14106
|
-
var siblingName = next ? 'nextSibling' : 'previousSibling';
|
14107
|
-
|
14108
|
-
for (node = start_node, parent = node.parentNode; node && node != end_node; node = parent) {
|
14109
|
-
parent = node.parentNode;
|
14110
|
-
siblings = collectSiblings(node == start_node ? node : node[siblingName], siblingName);
|
14111
|
-
|
14112
|
-
if (siblings.length) {
|
14113
|
-
if (!next) {
|
14114
|
-
siblings.reverse();
|
14115
|
-
}
|
14116
|
-
|
14117
|
-
callback(exclude(siblings));
|
14118
|
-
}
|
14119
|
-
}
|
14120
|
-
}
|
14121
|
-
|
14122
|
-
// If index based start position then resolve it
|
14123
|
-
if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) {
|
14124
|
-
startContainer = startContainer.childNodes[startOffset];
|
14125
|
-
}
|
14126
|
-
|
14127
|
-
// If index based end position then resolve it
|
14128
|
-
if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) {
|
14129
|
-
endContainer = endContainer.childNodes[Math.min(endOffset - 1, endContainer.childNodes.length - 1)];
|
14130
|
-
}
|
14131
|
-
|
14132
|
-
// Same container
|
14133
|
-
if (startContainer == endContainer) {
|
14134
|
-
return callback(exclude([startContainer]));
|
14135
|
-
}
|
14136
|
-
|
14137
|
-
// Find common ancestor and end points
|
14138
|
-
ancestor = dom.findCommonAncestor(startContainer, endContainer);
|
14139
|
-
|
14140
|
-
// Process left side
|
14141
|
-
for (node = startContainer; node; node = node.parentNode) {
|
14142
|
-
if (node === endContainer) {
|
14143
|
-
return walkBoundary(startContainer, ancestor, true);
|
14144
|
-
}
|
14145
|
-
|
14146
|
-
if (node === ancestor) {
|
14147
|
-
break;
|
14148
|
-
}
|
14149
|
-
}
|
14150
|
-
|
14151
|
-
// Process right side
|
14152
|
-
for (node = endContainer; node; node = node.parentNode) {
|
14153
|
-
if (node === startContainer) {
|
14154
|
-
return walkBoundary(endContainer, ancestor);
|
14155
|
-
}
|
14156
|
-
|
14157
|
-
if (node === ancestor) {
|
14158
|
-
break;
|
14159
|
-
}
|
14160
|
-
}
|
14161
|
-
|
14162
|
-
// Find start/end point
|
14163
|
-
startPoint = findEndPoint(startContainer, ancestor) || startContainer;
|
14164
|
-
endPoint = findEndPoint(endContainer, ancestor) || endContainer;
|
14165
|
-
|
14166
|
-
// Walk left leaf
|
14167
|
-
walkBoundary(startContainer, startPoint, true);
|
14168
|
-
|
14169
|
-
// Walk the middle from start to end point
|
14170
|
-
siblings = collectSiblings(
|
14171
|
-
startPoint == startContainer ? startPoint : startPoint.nextSibling,
|
14172
|
-
'nextSibling',
|
14173
|
-
endPoint == endContainer ? endPoint.nextSibling : endPoint
|
14174
|
-
);
|
14175
|
-
|
14176
|
-
if (siblings.length) {
|
14177
|
-
callback(exclude(siblings));
|
14178
|
-
}
|
14179
|
-
|
14180
|
-
// Walk right leaf
|
14181
|
-
walkBoundary(endContainer, endPoint);
|
14182
|
-
};
|
14183
|
-
|
14184
|
-
/**
|
14185
|
-
* Splits the specified range at it's start/end points.
|
14186
|
-
*
|
14187
|
-
* @private
|
14188
|
-
* @param {Range/RangeObject} rng Range to split.
|
14189
|
-
* @return {Object} Range position object.
|
14190
|
-
*/
|
14191
|
-
this.split = function(rng) {
|
14192
|
-
var startContainer = rng.startContainer,
|
14193
|
-
startOffset = rng.startOffset,
|
14194
|
-
endContainer = rng.endContainer,
|
14195
|
-
endOffset = rng.endOffset;
|
14196
|
-
|
14197
|
-
function splitText(node, offset) {
|
14198
|
-
return node.splitText(offset);
|
14199
|
-
}
|
14200
|
-
|
14201
|
-
// Handle single text node
|
14202
|
-
if (startContainer == endContainer && startContainer.nodeType == 3) {
|
14203
|
-
if (startOffset > 0 && startOffset < startContainer.nodeValue.length) {
|
14204
|
-
endContainer = splitText(startContainer, startOffset);
|
14205
|
-
startContainer = endContainer.previousSibling;
|
14206
|
-
|
14207
|
-
if (endOffset > startOffset) {
|
14208
|
-
endOffset = endOffset - startOffset;
|
14209
|
-
startContainer = endContainer = splitText(endContainer, endOffset).previousSibling;
|
14210
|
-
endOffset = endContainer.nodeValue.length;
|
14211
|
-
startOffset = 0;
|
14212
|
-
} else {
|
14213
|
-
endOffset = 0;
|
14214
|
-
}
|
14215
|
-
}
|
14216
|
-
} else {
|
14217
|
-
// Split startContainer text node if needed
|
14218
|
-
if (startContainer.nodeType == 3 && startOffset > 0 && startOffset < startContainer.nodeValue.length) {
|
14219
|
-
startContainer = splitText(startContainer, startOffset);
|
14220
|
-
startOffset = 0;
|
14221
|
-
}
|
14222
|
-
|
14223
|
-
// Split endContainer text node if needed
|
14224
|
-
if (endContainer.nodeType == 3 && endOffset > 0 && endOffset < endContainer.nodeValue.length) {
|
14225
|
-
endContainer = splitText(endContainer, endOffset).previousSibling;
|
14226
|
-
endOffset = endContainer.nodeValue.length;
|
14227
|
-
}
|
14228
|
-
}
|
14229
|
-
|
14230
|
-
return {
|
14231
|
-
startContainer: startContainer,
|
14232
|
-
startOffset: startOffset,
|
14233
|
-
endContainer: endContainer,
|
14234
|
-
endOffset: endOffset
|
14235
|
-
};
|
14236
|
-
};
|
14237
|
-
}
|
14238
|
-
|
14239
|
-
/**
|
14240
|
-
* Compares two ranges and checks if they are equal.
|
14241
|
-
*
|
14242
|
-
* @static
|
14243
|
-
* @method compareRanges
|
14244
|
-
* @param {DOMRange} rng1 First range to compare.
|
14245
|
-
* @param {DOMRange} rng2 First range to compare.
|
14246
|
-
* @return {Boolean} true/false if the ranges are equal.
|
14247
|
-
*/
|
14248
|
-
RangeUtils.compareRanges = function(rng1, rng2) {
|
14249
|
-
if (rng1 && rng2) {
|
14250
|
-
// Compare native IE ranges
|
14251
|
-
if (rng1.item || rng1.duplicate) {
|
14252
|
-
// Both are control ranges and the selected element matches
|
14253
|
-
if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0)) {
|
14254
|
-
return true;
|
14255
|
-
}
|
14256
|
-
|
14257
|
-
// Both are text ranges and the range matches
|
14258
|
-
if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1)) {
|
14259
|
-
return true;
|
14260
|
-
}
|
14261
|
-
} else {
|
14262
|
-
// Compare w3c ranges
|
14263
|
-
return rng1.startContainer == rng2.startContainer && rng1.startOffset == rng2.startOffset;
|
14264
|
-
}
|
14265
|
-
}
|
14266
|
-
|
14267
|
-
return false;
|
14268
|
-
};
|
14269
|
-
|
14270
|
-
return RangeUtils;
|
14271
|
-
});
|
14272
|
-
|
14273
14318
|
// Included from: js/tinymce/classes/Formatter.js
|
14274
14319
|
|
14275
14320
|
/**
|
@@ -14415,7 +14460,7 @@ define("tinymce/Formatter", [
|
|
14415
14460
|
|
14416
14461
|
removeformat: [
|
14417
14462
|
{
|
14418
|
-
selector: 'b,strong,em,i,font,u,strike,sub,sup',
|
14463
|
+
selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q',
|
14419
14464
|
remove: 'all',
|
14420
14465
|
split: true,
|
14421
14466
|
expand: false,
|
@@ -14830,7 +14875,7 @@ define("tinymce/Formatter", [
|
|
14830
14875
|
});
|
14831
14876
|
|
14832
14877
|
// If child was found and of the same type as the current node
|
14833
|
-
if (child && matchName(child, format)) {
|
14878
|
+
if (child && !isBookmarkNode(child) && matchName(child, format)) {
|
14834
14879
|
clone = dom.clone(child, FALSE);
|
14835
14880
|
setElementFormat(clone);
|
14836
14881
|
|
@@ -14865,6 +14910,10 @@ define("tinymce/Formatter", [
|
|
14865
14910
|
each(dom.select(format.inline, node), function(child) {
|
14866
14911
|
var parent;
|
14867
14912
|
|
14913
|
+
if (isBookmarkNode(child)) {
|
14914
|
+
return;
|
14915
|
+
}
|
14916
|
+
|
14868
14917
|
// When wrap_links is set to false we don't want
|
14869
14918
|
// to remove the format on children within links
|
14870
14919
|
if (format.wrap_links === false) {
|
@@ -16166,7 +16215,7 @@ define("tinymce/Formatter", [
|
|
16166
16215
|
next = next ? 'nextSibling' : 'previousSibling';
|
16167
16216
|
|
16168
16217
|
for (node = inc ? node : node[next]; node; node = node[next]) {
|
16169
|
-
if (node.nodeType == 1
|
16218
|
+
if (node.nodeType == 1 || !isWhiteSpaceNode(node)) {
|
16170
16219
|
return node;
|
16171
16220
|
}
|
16172
16221
|
}
|
@@ -16284,7 +16333,7 @@ define("tinymce/Formatter", [
|
|
16284
16333
|
return FALSE;
|
16285
16334
|
}
|
16286
16335
|
|
16287
|
-
return
|
16336
|
+
return !isBookmarkNode(node1) && !isBookmarkNode(node2);
|
16288
16337
|
}
|
16289
16338
|
|
16290
16339
|
function findElementSibling(node, sibling_name) {
|
@@ -16731,9 +16780,9 @@ define("tinymce/UndoManager", [
|
|
16731
16780
|
return trim(editor.getContent({format: 'raw', no_events: 1}).replace(trimContentRegExp, ''));
|
16732
16781
|
}
|
16733
16782
|
|
16734
|
-
function addNonTypingUndoLevel() {
|
16783
|
+
function addNonTypingUndoLevel(e) {
|
16735
16784
|
self.typing = false;
|
16736
|
-
self.add();
|
16785
|
+
self.add({}, e);
|
16737
16786
|
}
|
16738
16787
|
|
16739
16788
|
// Add initial undo level when the editor is initialized
|
@@ -16755,7 +16804,7 @@ define("tinymce/UndoManager", [
|
|
16755
16804
|
var cmd = e.command;
|
16756
16805
|
|
16757
16806
|
if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint') {
|
16758
|
-
|
16807
|
+
addNonTypingUndoLevel(e);
|
16759
16808
|
}
|
16760
16809
|
});
|
16761
16810
|
|
@@ -16763,13 +16812,8 @@ define("tinymce/UndoManager", [
|
|
16763
16812
|
self.beforeChange();
|
16764
16813
|
});
|
16765
16814
|
|
16766
|
-
editor.on('SaveContent ObjectResized', addNonTypingUndoLevel);
|
16815
|
+
editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
|
16767
16816
|
editor.dom.bind(editor.dom.getRoot(), 'dragend', addNonTypingUndoLevel);
|
16768
|
-
editor.dom.bind(editor.getBody(), 'focusout', function() {
|
16769
|
-
if (!editor.removed && self.typing) {
|
16770
|
-
addNonTypingUndoLevel();
|
16771
|
-
}
|
16772
|
-
});
|
16773
16817
|
|
16774
16818
|
editor.on('KeyUp', function(e) {
|
16775
16819
|
var keyCode = e.keyCode;
|
@@ -16807,7 +16851,7 @@ define("tinymce/UndoManager", [
|
|
16807
16851
|
// Is caracter positon keys left,right,up,down,home,end,pgdown,pgup,enter
|
16808
16852
|
if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 45) {
|
16809
16853
|
if (self.typing) {
|
16810
|
-
addNonTypingUndoLevel();
|
16854
|
+
addNonTypingUndoLevel(e);
|
16811
16855
|
}
|
16812
16856
|
|
16813
16857
|
return;
|
@@ -16817,14 +16861,14 @@ define("tinymce/UndoManager", [
|
|
16817
16861
|
if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing) {
|
16818
16862
|
self.beforeChange();
|
16819
16863
|
self.typing = true;
|
16820
|
-
self.add();
|
16864
|
+
self.add({}, e);
|
16821
16865
|
isFirstTypedCharacter = true;
|
16822
16866
|
}
|
16823
16867
|
});
|
16824
16868
|
|
16825
|
-
editor.on('MouseDown', function() {
|
16869
|
+
editor.on('MouseDown', function(e) {
|
16826
16870
|
if (self.typing) {
|
16827
|
-
addNonTypingUndoLevel();
|
16871
|
+
addNonTypingUndoLevel(e);
|
16828
16872
|
}
|
16829
16873
|
});
|
16830
16874
|
|
@@ -16866,16 +16910,21 @@ define("tinymce/UndoManager", [
|
|
16866
16910
|
* Adds a new undo level/snapshot to the undo list.
|
16867
16911
|
*
|
16868
16912
|
* @method add
|
16869
|
-
* @param {Object}
|
16913
|
+
* @param {Object} level Optional undo level object to add.
|
16914
|
+
* @param {DOMEvent} Event Optional event responsible for the creation of the undo level.
|
16870
16915
|
* @return {Object} Undo level that got added or null it a level wasn't needed.
|
16871
16916
|
*/
|
16872
|
-
add: function(level) {
|
16917
|
+
add: function(level, event) {
|
16873
16918
|
var i, settings = editor.settings, lastLevel;
|
16874
16919
|
|
16875
16920
|
level = level || {};
|
16876
16921
|
level.content = getContent();
|
16877
16922
|
|
16878
|
-
if (lock || editor.
|
16923
|
+
if (lock || editor.removed) {
|
16924
|
+
return null;
|
16925
|
+
}
|
16926
|
+
|
16927
|
+
if (editor.fire('BeforeAddUndo', {level: level, originalEvent: event}).isDefaultPrevented()) {
|
16879
16928
|
return null;
|
16880
16929
|
}
|
16881
16930
|
|
@@ -16913,13 +16962,13 @@ define("tinymce/UndoManager", [
|
|
16913
16962
|
data.push(level);
|
16914
16963
|
index = data.length - 1;
|
16915
16964
|
|
16916
|
-
var args = {level: level, lastLevel: lastLevel};
|
16965
|
+
var args = {level: level, lastLevel: lastLevel, originalEvent: event};
|
16917
16966
|
|
16918
16967
|
editor.fire('AddUndo', args);
|
16919
16968
|
|
16920
16969
|
if (index > 0) {
|
16921
|
-
editor.fire('change', args);
|
16922
16970
|
editor.isNotDirty = false;
|
16971
|
+
editor.fire('change', args);
|
16923
16972
|
}
|
16924
16973
|
|
16925
16974
|
return level;
|
@@ -17051,8 +17100,9 @@ define("tinymce/UndoManager", [
|
|
17051
17100
|
*/
|
17052
17101
|
define("tinymce/EnterKey", [
|
17053
17102
|
"tinymce/dom/TreeWalker",
|
17103
|
+
"tinymce/dom/RangeUtils",
|
17054
17104
|
"tinymce/Env"
|
17055
|
-
], function(TreeWalker, Env) {
|
17105
|
+
], function(TreeWalker, RangeUtils, Env) {
|
17056
17106
|
var isIE = Env.ie && Env.ie < 11;
|
17057
17107
|
|
17058
17108
|
return function(editor) {
|
@@ -17060,7 +17110,7 @@ define("tinymce/EnterKey", [
|
|
17060
17110
|
var undoManager = editor.undoManager, schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
|
17061
17111
|
|
17062
17112
|
function handleEnterKey(evt) {
|
17063
|
-
var rng
|
17113
|
+
var rng, tmpRng, editableRoot, container, offset, parentBlock, documentMode, shiftKey,
|
17064
17114
|
newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
|
17065
17115
|
|
17066
17116
|
// Returns true if the block can be split into two blocks or not
|
@@ -17225,7 +17275,7 @@ define("tinymce/EnterKey", [
|
|
17225
17275
|
// Clone any parent styles
|
17226
17276
|
if (settings.keep_styles !== false) {
|
17227
17277
|
do {
|
17228
|
-
if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) {
|
17278
|
+
if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U|VAR|CITE|DFN|CODE|MARK|Q|SUP|SUB|SAMP)$/.test(node.nodeName)) {
|
17229
17279
|
// Never clone a caret containers
|
17230
17280
|
if (node.id == '_mce_caret') {
|
17231
17281
|
continue;
|
@@ -17542,18 +17592,21 @@ define("tinymce/EnterKey", [
|
|
17542
17592
|
}
|
17543
17593
|
}
|
17544
17594
|
|
17545
|
-
|
17546
|
-
if (!rng.collapsed) {
|
17547
|
-
editor.execCommand('Delete');
|
17548
|
-
return;
|
17549
|
-
}
|
17595
|
+
rng = selection.getRng(true);
|
17550
17596
|
|
17551
17597
|
// Event is blocked by some other handler for example the lists plugin
|
17552
17598
|
if (evt.isDefaultPrevented()) {
|
17553
17599
|
return;
|
17554
17600
|
}
|
17555
17601
|
|
17602
|
+
// Delete any selected contents
|
17603
|
+
if (!rng.collapsed) {
|
17604
|
+
editor.execCommand('Delete');
|
17605
|
+
return;
|
17606
|
+
}
|
17607
|
+
|
17556
17608
|
// Setup range items and newBlockName
|
17609
|
+
new RangeUtils(dom).normalize(rng);
|
17557
17610
|
container = rng.startContainer;
|
17558
17611
|
offset = rng.startOffset;
|
17559
17612
|
newBlockName = (settings.force_p_newlines ? 'p' : '') || settings.forced_root_block;
|
@@ -17564,6 +17617,7 @@ define("tinymce/EnterKey", [
|
|
17564
17617
|
// Resolve node index
|
17565
17618
|
if (container.nodeType == 1 && container.hasChildNodes()) {
|
17566
17619
|
isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
|
17620
|
+
|
17567
17621
|
container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
|
17568
17622
|
if (isAfterLastNodeInContainer && container.nodeType == 3) {
|
17569
17623
|
offset = container.nodeValue.length;
|
@@ -20070,7 +20124,7 @@ define("tinymce/ui/Control", [
|
|
20070
20124
|
self.settings = settings = Tools.extend({}, self.Defaults, settings);
|
20071
20125
|
|
20072
20126
|
// Initial states
|
20073
|
-
self._id = DomUtils.id();
|
20127
|
+
self._id = settings.id || DomUtils.id();
|
20074
20128
|
self._text = self._name = '';
|
20075
20129
|
self._width = self._height = 0;
|
20076
20130
|
self._aria = {role: settings.role};
|
@@ -21026,7 +21080,7 @@ define("tinymce/ui/Control", [
|
|
21026
21080
|
* @return {tinymce.ui.Control} Current control instance.
|
21027
21081
|
*/
|
21028
21082
|
aria: function(name, value) {
|
21029
|
-
var self = this, elm = self.getEl();
|
21083
|
+
var self = this, elm = self.getEl(self.ariaTarget);
|
21030
21084
|
|
21031
21085
|
if (typeof(value) === "undefined") {
|
21032
21086
|
return self._aria[name];
|
@@ -21035,10 +21089,6 @@ define("tinymce/ui/Control", [
|
|
21035
21089
|
}
|
21036
21090
|
|
21037
21091
|
if (self._rendered) {
|
21038
|
-
if (name == 'label') {
|
21039
|
-
elm.setAttribute('aria-labelledby', self._id);
|
21040
|
-
}
|
21041
|
-
|
21042
21092
|
elm.setAttribute(name == 'role' ? name : 'aria-' + name, value);
|
21043
21093
|
}
|
21044
21094
|
|
@@ -21669,6 +21719,399 @@ define("tinymce/ui/Factory", [], function() {
|
|
21669
21719
|
};
|
21670
21720
|
});
|
21671
21721
|
|
21722
|
+
// Included from: js/tinymce/classes/ui/KeyboardNavigation.js
|
21723
|
+
|
21724
|
+
/**
|
21725
|
+
* KeyboardNavigation.js
|
21726
|
+
*
|
21727
|
+
* Copyright, Moxiecode Systems AB
|
21728
|
+
* Released under LGPL License.
|
21729
|
+
*
|
21730
|
+
* License: http://www.tinymce.com/license
|
21731
|
+
* Contributing: http://www.tinymce.com/contributing
|
21732
|
+
*/
|
21733
|
+
|
21734
|
+
/**
|
21735
|
+
* This class handles keyboard navigation of controls and elements.
|
21736
|
+
*
|
21737
|
+
* @class tinymce.ui.KeyboardNavigation
|
21738
|
+
*/
|
21739
|
+
define("tinymce/ui/KeyboardNavigation", [
|
21740
|
+
], function() {
|
21741
|
+
"use strict";
|
21742
|
+
|
21743
|
+
/**
|
21744
|
+
* This class handles all keyboard navigation for WAI-ARIA support. Each root container
|
21745
|
+
* gets an instance of this class.
|
21746
|
+
*
|
21747
|
+
* @constructor
|
21748
|
+
*/
|
21749
|
+
return function(settings) {
|
21750
|
+
var root = settings.root, focusedElement, focusedControl;
|
21751
|
+
|
21752
|
+
focusedElement = document.activeElement;
|
21753
|
+
focusedControl = root.getParentCtrl(focusedElement);
|
21754
|
+
|
21755
|
+
/**
|
21756
|
+
* Returns the currently focused elements wai aria role of the currently
|
21757
|
+
* focused element or specified element.
|
21758
|
+
*
|
21759
|
+
* @private
|
21760
|
+
* @param {Element} elm Optional element to get role from.
|
21761
|
+
* @return {String} Role of specified element.
|
21762
|
+
*/
|
21763
|
+
function getRole(elm) {
|
21764
|
+
elm = elm || focusedElement;
|
21765
|
+
|
21766
|
+
return elm && elm.getAttribute('role');
|
21767
|
+
}
|
21768
|
+
|
21769
|
+
/**
|
21770
|
+
* Returns the wai role of the parent element of the currently
|
21771
|
+
* focused element or specified element.
|
21772
|
+
*
|
21773
|
+
* @private
|
21774
|
+
* @param {Element} elm Optional element to get parent role from.
|
21775
|
+
* @return {String} Role of the first parent that has a role.
|
21776
|
+
*/
|
21777
|
+
function getParentRole(elm) {
|
21778
|
+
var role, parent = elm || focusedElement;
|
21779
|
+
|
21780
|
+
while ((parent = parent.parentNode)) {
|
21781
|
+
if ((role = getRole(parent))) {
|
21782
|
+
return role;
|
21783
|
+
}
|
21784
|
+
}
|
21785
|
+
}
|
21786
|
+
|
21787
|
+
/**
|
21788
|
+
* Returns a wai aria property by name for example aria-selected.
|
21789
|
+
*
|
21790
|
+
* @private
|
21791
|
+
* @param {String} name Name of the aria property to get for example "disabled".
|
21792
|
+
* @return {String} Aria property value.
|
21793
|
+
*/
|
21794
|
+
function getAriaProp(name) {
|
21795
|
+
var elm = focusedElement;
|
21796
|
+
|
21797
|
+
if (elm) {
|
21798
|
+
return elm.getAttribute('aria-' + name);
|
21799
|
+
}
|
21800
|
+
}
|
21801
|
+
|
21802
|
+
/**
|
21803
|
+
* Is the element a text input element or not.
|
21804
|
+
*
|
21805
|
+
* @private
|
21806
|
+
* @param {Element} elm Element to check if it's an text input element or not.
|
21807
|
+
* @return {Boolean} True/false if the element is a text element or not.
|
21808
|
+
*/
|
21809
|
+
function isTextInputElement(elm) {
|
21810
|
+
// Notice: since type can be "email" etc we don't check the type
|
21811
|
+
// So all input elements gets treated as text input elements
|
21812
|
+
return elm.tagName == "INPUT" || elm.tagName == "TEXTAREA";
|
21813
|
+
}
|
21814
|
+
|
21815
|
+
/**
|
21816
|
+
* Returns true/false if the specified element can be focused or not.
|
21817
|
+
*
|
21818
|
+
* @private
|
21819
|
+
* @param {Element} elm DOM element to check if it can be focused or not.
|
21820
|
+
* @return {Boolean} True/false if the element can have focus.
|
21821
|
+
*/
|
21822
|
+
function canFocus(elm) {
|
21823
|
+
if (isTextInputElement(elm) && !elm.hidden) {
|
21824
|
+
return true;
|
21825
|
+
}
|
21826
|
+
|
21827
|
+
if (/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell)$/.test(getRole(elm))) {
|
21828
|
+
return true;
|
21829
|
+
}
|
21830
|
+
|
21831
|
+
return false;
|
21832
|
+
}
|
21833
|
+
|
21834
|
+
/**
|
21835
|
+
* Returns an array of focusable visible elements within the specified container element.
|
21836
|
+
*
|
21837
|
+
* @private
|
21838
|
+
* @param {Element} elm DOM element to find focusable elements within.
|
21839
|
+
* @return {Array} Array of focusable elements.
|
21840
|
+
*/
|
21841
|
+
function getFocusElements(elm) {
|
21842
|
+
var elements = [];
|
21843
|
+
|
21844
|
+
function collect(elm) {
|
21845
|
+
if (elm.nodeType != 1 || elm.style.display == 'none') {
|
21846
|
+
return;
|
21847
|
+
}
|
21848
|
+
|
21849
|
+
if (canFocus(elm)) {
|
21850
|
+
elements.push(elm);
|
21851
|
+
}
|
21852
|
+
|
21853
|
+
for (var i = 0; i < elm.childNodes.length; i++) {
|
21854
|
+
collect(elm.childNodes[i]);
|
21855
|
+
}
|
21856
|
+
}
|
21857
|
+
|
21858
|
+
collect(elm || root.getEl());
|
21859
|
+
|
21860
|
+
return elements;
|
21861
|
+
}
|
21862
|
+
|
21863
|
+
/**
|
21864
|
+
* Returns the navigation root control for the specified control. The navigation root
|
21865
|
+
* is the control that the keyboard navigation gets scoped to for example a menubar or toolbar group.
|
21866
|
+
* It will look for parents of the specified target control or the currenty focused control if this option is omitted.
|
21867
|
+
*
|
21868
|
+
* @private
|
21869
|
+
* @param {tinymce.ui.Control} targetControl Optional target control to find root of.
|
21870
|
+
* @return {tinymce.ui.Control} Navigation root control.
|
21871
|
+
*/
|
21872
|
+
function getNavigationRoot(targetControl) {
|
21873
|
+
var navigationRoot, controls;
|
21874
|
+
|
21875
|
+
targetControl = targetControl || focusedControl;
|
21876
|
+
controls = targetControl.parents().toArray();
|
21877
|
+
controls.unshift(targetControl);
|
21878
|
+
|
21879
|
+
for (var i = 0; i < controls.length; i++) {
|
21880
|
+
navigationRoot = controls[i];
|
21881
|
+
|
21882
|
+
if (navigationRoot.settings.ariaRoot) {
|
21883
|
+
break;
|
21884
|
+
}
|
21885
|
+
}
|
21886
|
+
|
21887
|
+
return navigationRoot;
|
21888
|
+
}
|
21889
|
+
|
21890
|
+
/**
|
21891
|
+
* Focuses the first item in the specified targetControl element or the last aria index if the
|
21892
|
+
* navigation root has the ariaRemember option enabled.
|
21893
|
+
*
|
21894
|
+
* @private
|
21895
|
+
* @param {tinymce.ui.Control} targetControl Target control to focus the first item in.
|
21896
|
+
*/
|
21897
|
+
function focusFirst(targetControl) {
|
21898
|
+
var navigationRoot = getNavigationRoot(targetControl);
|
21899
|
+
var focusElements = getFocusElements(navigationRoot.getEl());
|
21900
|
+
|
21901
|
+
if (navigationRoot.settings.ariaRemember && "lastAriaIndex" in navigationRoot) {
|
21902
|
+
moveFocusToIndex(navigationRoot.lastAriaIndex, focusElements);
|
21903
|
+
} else {
|
21904
|
+
moveFocusToIndex(0, focusElements);
|
21905
|
+
}
|
21906
|
+
}
|
21907
|
+
|
21908
|
+
/**
|
21909
|
+
* Moves the focus to the specified index within the elements list.
|
21910
|
+
* This will scope the index to the size of the element list if it changed.
|
21911
|
+
*
|
21912
|
+
* @private
|
21913
|
+
* @param {Number} idx Specified index to move to.
|
21914
|
+
* @param {Array} elements Array with dom elements to move focus within.
|
21915
|
+
* @return {Number} Input index or a changed index if it was out of range.
|
21916
|
+
*/
|
21917
|
+
function moveFocusToIndex(idx, elements) {
|
21918
|
+
if (idx < 0) {
|
21919
|
+
idx = elements.length - 1;
|
21920
|
+
} else if (idx >= elements.length) {
|
21921
|
+
idx = 0;
|
21922
|
+
}
|
21923
|
+
|
21924
|
+
if (elements[idx]) {
|
21925
|
+
elements[idx].focus();
|
21926
|
+
}
|
21927
|
+
|
21928
|
+
return idx;
|
21929
|
+
}
|
21930
|
+
|
21931
|
+
/**
|
21932
|
+
* Moves the focus forwards or backwards.
|
21933
|
+
*
|
21934
|
+
* @private
|
21935
|
+
* @param {Number} dir Direction to move in positive means forward, negative means backwards.
|
21936
|
+
* @param {Array} elements Optional array of elements to move within defaults to the current navigation roots elements.
|
21937
|
+
*/
|
21938
|
+
function moveFocus(dir, elements) {
|
21939
|
+
var idx = -1, navigationRoot = getNavigationRoot();
|
21940
|
+
|
21941
|
+
elements = elements || getFocusElements(navigationRoot.getEl());
|
21942
|
+
|
21943
|
+
for (var i = 0; i < elements.length; i++) {
|
21944
|
+
if (elements[i] === focusedElement) {
|
21945
|
+
idx = i;
|
21946
|
+
}
|
21947
|
+
}
|
21948
|
+
|
21949
|
+
idx += dir;
|
21950
|
+
navigationRoot.lastAriaIndex = moveFocusToIndex(idx, elements);
|
21951
|
+
}
|
21952
|
+
|
21953
|
+
/**
|
21954
|
+
* Moves the focus to the left this is called by the left key.
|
21955
|
+
*
|
21956
|
+
* @private
|
21957
|
+
*/
|
21958
|
+
function left() {
|
21959
|
+
var parentRole = getParentRole();
|
21960
|
+
|
21961
|
+
if (parentRole == "tablist") {
|
21962
|
+
moveFocus(-1, getFocusElements(focusedElement.parentNode));
|
21963
|
+
} else if (focusedControl.parent().submenu) {
|
21964
|
+
cancel();
|
21965
|
+
} else {
|
21966
|
+
moveFocus(-1);
|
21967
|
+
}
|
21968
|
+
}
|
21969
|
+
|
21970
|
+
/**
|
21971
|
+
* Moves the focus to the right this is called by the right key.
|
21972
|
+
*
|
21973
|
+
* @private
|
21974
|
+
*/
|
21975
|
+
function right() {
|
21976
|
+
var role = getRole(), parentRole = getParentRole();
|
21977
|
+
|
21978
|
+
if (parentRole == "tablist") {
|
21979
|
+
moveFocus(1, getFocusElements(focusedElement.parentNode));
|
21980
|
+
} else if (role == "menuitem" && parentRole == "menu" && getAriaProp('haspopup')) {
|
21981
|
+
enter();
|
21982
|
+
} else {
|
21983
|
+
moveFocus(1);
|
21984
|
+
}
|
21985
|
+
}
|
21986
|
+
|
21987
|
+
/**
|
21988
|
+
* Moves the focus to the up this is called by the up key.
|
21989
|
+
*
|
21990
|
+
* @private
|
21991
|
+
*/
|
21992
|
+
function up() {
|
21993
|
+
moveFocus(-1);
|
21994
|
+
}
|
21995
|
+
|
21996
|
+
/**
|
21997
|
+
* Moves the focus to the up this is called by the down key.
|
21998
|
+
*
|
21999
|
+
* @private
|
22000
|
+
*/
|
22001
|
+
function down() {
|
22002
|
+
var role = getRole(), parentRole = getParentRole();
|
22003
|
+
|
22004
|
+
if (role == "menuitem" && parentRole == "menubar") {
|
22005
|
+
enter();
|
22006
|
+
} else if (role == "button" && getAriaProp('haspopup')) {
|
22007
|
+
enter({key: 'down'});
|
22008
|
+
} else {
|
22009
|
+
moveFocus(1);
|
22010
|
+
}
|
22011
|
+
}
|
22012
|
+
|
22013
|
+
/**
|
22014
|
+
* Moves the focus to the next item or previous item depending on shift key.
|
22015
|
+
*
|
22016
|
+
* @private
|
22017
|
+
* @param {DOMEvent} e DOM event object.
|
22018
|
+
*/
|
22019
|
+
function tab(e) {
|
22020
|
+
var parentRole = getParentRole();
|
22021
|
+
|
22022
|
+
if (parentRole == "tablist") {
|
22023
|
+
var elm = getFocusElements(focusedControl.getEl('body'))[0];
|
22024
|
+
|
22025
|
+
if (elm) {
|
22026
|
+
elm.focus();
|
22027
|
+
}
|
22028
|
+
} else {
|
22029
|
+
moveFocus(e.shiftKey ? -1 : 1);
|
22030
|
+
}
|
22031
|
+
}
|
22032
|
+
|
22033
|
+
/**
|
22034
|
+
* Calls the cancel event on the currently focused control. This is normally done using the Esc key.
|
22035
|
+
*
|
22036
|
+
* @private
|
22037
|
+
*/
|
22038
|
+
function cancel() {
|
22039
|
+
focusedControl.fire('cancel');
|
22040
|
+
}
|
22041
|
+
|
22042
|
+
/**
|
22043
|
+
* Calls the click event on the currently focused control. This is normally done using the Enter/Space keys.
|
22044
|
+
*
|
22045
|
+
* @private
|
22046
|
+
* @param {Object} aria Optional aria data to pass along with the enter event.
|
22047
|
+
*/
|
22048
|
+
function enter(aria) {
|
22049
|
+
aria = aria || {};
|
22050
|
+
focusedControl.fire('click', {target: focusedElement, aria: aria});
|
22051
|
+
}
|
22052
|
+
|
22053
|
+
root.on('keydown', function(e) {
|
22054
|
+
function handleNonTabEvent(e, handler) {
|
22055
|
+
// Ignore non tab keys for text elements
|
22056
|
+
if (isTextInputElement(focusedElement)) {
|
22057
|
+
return;
|
22058
|
+
}
|
22059
|
+
|
22060
|
+
if (handler(e) !== false) {
|
22061
|
+
e.preventDefault();
|
22062
|
+
}
|
22063
|
+
}
|
22064
|
+
|
22065
|
+
if (e.isDefaultPrevented()) {
|
22066
|
+
return;
|
22067
|
+
}
|
22068
|
+
|
22069
|
+
switch (e.keyCode) {
|
22070
|
+
case 37: // DOM_VK_LEFT
|
22071
|
+
handleNonTabEvent(e, left);
|
22072
|
+
break;
|
22073
|
+
|
22074
|
+
case 39: // DOM_VK_RIGHT
|
22075
|
+
handleNonTabEvent(e, right);
|
22076
|
+
break;
|
22077
|
+
|
22078
|
+
case 38: // DOM_VK_UP
|
22079
|
+
handleNonTabEvent(e, up);
|
22080
|
+
break;
|
22081
|
+
|
22082
|
+
case 40: // DOM_VK_DOWN
|
22083
|
+
handleNonTabEvent(e, down);
|
22084
|
+
break;
|
22085
|
+
|
22086
|
+
case 27: // DOM_VK_ESCAPE
|
22087
|
+
handleNonTabEvent(e, cancel);
|
22088
|
+
break;
|
22089
|
+
|
22090
|
+
case 14: // DOM_VK_ENTER
|
22091
|
+
case 13: // DOM_VK_RETURN
|
22092
|
+
case 32: // DOM_VK_SPACE
|
22093
|
+
handleNonTabEvent(e, enter);
|
22094
|
+
break;
|
22095
|
+
|
22096
|
+
case 9: // DOM_VK_TAB
|
22097
|
+
if (tab(e) !== false) {
|
22098
|
+
e.preventDefault();
|
22099
|
+
}
|
22100
|
+
break;
|
22101
|
+
}
|
22102
|
+
});
|
22103
|
+
|
22104
|
+
root.on('focusin', function(e) {
|
22105
|
+
focusedElement = e.target;
|
22106
|
+
focusedControl = e.control;
|
22107
|
+
});
|
22108
|
+
|
22109
|
+
return {
|
22110
|
+
focusFirst: focusFirst
|
22111
|
+
};
|
22112
|
+
};
|
22113
|
+
});
|
22114
|
+
|
21672
22115
|
// Included from: js/tinymce/classes/ui/Container.js
|
21673
22116
|
|
21674
22117
|
/**
|
@@ -21695,9 +22138,10 @@ define("tinymce/ui/Container", [
|
|
21695
22138
|
"tinymce/ui/Collection",
|
21696
22139
|
"tinymce/ui/Selector",
|
21697
22140
|
"tinymce/ui/Factory",
|
22141
|
+
"tinymce/ui/KeyboardNavigation",
|
21698
22142
|
"tinymce/util/Tools",
|
21699
22143
|
"tinymce/ui/DomUtils"
|
21700
|
-
], function(Control, Collection, Selector, Factory, Tools, DomUtils) {
|
22144
|
+
], function(Control, Collection, Selector, Factory, KeyboardNavigation, Tools, DomUtils) {
|
21701
22145
|
"use strict";
|
21702
22146
|
|
21703
22147
|
var selectorCache = {};
|
@@ -21788,15 +22232,41 @@ define("tinymce/ui/Container", [
|
|
21788
22232
|
* for the first control in the container and focus that.
|
21789
22233
|
*
|
21790
22234
|
* @method focus
|
22235
|
+
* @param {Boolean} keyboard Optional true/false if the focus was a keyboard focus or not.
|
21791
22236
|
* @return {tinymce.ui.Collection} Current instance.
|
21792
22237
|
*/
|
21793
|
-
focus: function() {
|
21794
|
-
var self = this;
|
22238
|
+
focus: function(keyboard) {
|
22239
|
+
var self = this, focusCtrl, keyboardNav, items;
|
21795
22240
|
|
21796
|
-
if (
|
21797
|
-
self.
|
21798
|
-
|
21799
|
-
|
22241
|
+
if (keyboard) {
|
22242
|
+
keyboardNav = self.keyboardNav || self.parents().eq(-1)[0].keyboardNav;
|
22243
|
+
|
22244
|
+
if (keyboardNav) {
|
22245
|
+
keyboardNav.focusFirst(self);
|
22246
|
+
return;
|
22247
|
+
}
|
22248
|
+
}
|
22249
|
+
|
22250
|
+
items = self.find('*');
|
22251
|
+
|
22252
|
+
// TODO: Figure out a better way to auto focus alert dialog buttons
|
22253
|
+
if (self.statusbar) {
|
22254
|
+
items.add(self.statusbar.items());
|
22255
|
+
}
|
22256
|
+
|
22257
|
+
items.each(function(ctrl) {
|
22258
|
+
if (ctrl.settings.autofocus) {
|
22259
|
+
focusCtrl = null;
|
22260
|
+
return false;
|
22261
|
+
}
|
22262
|
+
|
22263
|
+
if (ctrl.canFocus) {
|
22264
|
+
focusCtrl = focusCtrl || ctrl;
|
22265
|
+
}
|
22266
|
+
});
|
22267
|
+
|
22268
|
+
if (focusCtrl) {
|
22269
|
+
focusCtrl.focus();
|
21800
22270
|
}
|
21801
22271
|
|
21802
22272
|
return self;
|
@@ -22059,6 +22529,12 @@ define("tinymce/ui/Container", [
|
|
22059
22529
|
});
|
22060
22530
|
}
|
22061
22531
|
|
22532
|
+
if (!self.parent()) {
|
22533
|
+
self.keyboardNav = new KeyboardNavigation({
|
22534
|
+
root: self
|
22535
|
+
});
|
22536
|
+
}
|
22537
|
+
|
22062
22538
|
return self;
|
22063
22539
|
},
|
22064
22540
|
|
@@ -22486,7 +22962,7 @@ define("tinymce/ui/Panel", [
|
|
22486
22962
|
}
|
22487
22963
|
|
22488
22964
|
return (
|
22489
|
-
'<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
|
22965
|
+
'<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1" role="group">' +
|
22490
22966
|
(self._preBodyHtml || '') +
|
22491
22967
|
innerHtml +
|
22492
22968
|
'</div>'
|
@@ -23085,6 +23561,16 @@ define("tinymce/ui/FloatPanel", [
|
|
23085
23561
|
remove: function() {
|
23086
23562
|
removeVisiblePanel(this);
|
23087
23563
|
this._super();
|
23564
|
+
},
|
23565
|
+
|
23566
|
+
postRender: function() {
|
23567
|
+
var self = this;
|
23568
|
+
|
23569
|
+
if (self.settings.bodyRole) {
|
23570
|
+
this.getEl('body').setAttribute('role', self.settings.bodyRole);
|
23571
|
+
}
|
23572
|
+
|
23573
|
+
return self._super();
|
23088
23574
|
}
|
23089
23575
|
});
|
23090
23576
|
|
@@ -23100,8 +23586,7 @@ define("tinymce/ui/FloatPanel", [
|
|
23100
23586
|
while (i--) {
|
23101
23587
|
var panel = visiblePanels[i];
|
23102
23588
|
|
23103
|
-
if (panel.settings.autohide) {
|
23104
|
-
panel.fire('cancel', {}, false);
|
23589
|
+
if (panel && panel.settings.autohide) {
|
23105
23590
|
panel.hide();
|
23106
23591
|
visiblePanels.splice(i, 1);
|
23107
23592
|
}
|
@@ -23129,347 +23614,6 @@ define("tinymce/ui/FloatPanel", [
|
|
23129
23614
|
return FloatPanel;
|
23130
23615
|
});
|
23131
23616
|
|
23132
|
-
// Included from: js/tinymce/classes/ui/KeyboardNavigation.js
|
23133
|
-
|
23134
|
-
/**
|
23135
|
-
* KeyboardNavigation.js
|
23136
|
-
*
|
23137
|
-
* Copyright, Moxiecode Systems AB
|
23138
|
-
* Released under LGPL License.
|
23139
|
-
*
|
23140
|
-
* License: http://www.tinymce.com/license
|
23141
|
-
* Contributing: http://www.tinymce.com/contributing
|
23142
|
-
*/
|
23143
|
-
|
23144
|
-
/**
|
23145
|
-
* This class handles keyboard navigation of controls and elements.
|
23146
|
-
*
|
23147
|
-
* @class tinymce.ui.KeyboardNavigation
|
23148
|
-
*/
|
23149
|
-
define("tinymce/ui/KeyboardNavigation", [
|
23150
|
-
"tinymce/ui/DomUtils"
|
23151
|
-
], function(DomUtils) {
|
23152
|
-
"use strict";
|
23153
|
-
|
23154
|
-
/**
|
23155
|
-
* Create a new KeyboardNavigation instance to handle the focus for a specific element.
|
23156
|
-
*
|
23157
|
-
* @constructor
|
23158
|
-
* @param {Object} settings the settings object to define how keyboard navigation works.
|
23159
|
-
*
|
23160
|
-
* @setting {tinymce.ui.Control} root the root control navigation focus movement is scoped to this root.
|
23161
|
-
* @setting {Array} items an array containing the items to move focus between. Every object in this array must have an
|
23162
|
-
* id attribute which maps to the actual DOM element and it must be able to have focus i.e. tabIndex=-1.
|
23163
|
-
* @setting {Function} onCancel the callback for when the user presses escape or otherwise indicates canceling.
|
23164
|
-
* @setting {Function} onAction (optional) the action handler to call when the user activates an item.
|
23165
|
-
* @setting {Boolean} enableLeftRight (optional, default) when true, the up/down arrows move through items.
|
23166
|
-
* @setting {Boolean} enableUpDown (optional) when true, the up/down arrows move through items.
|
23167
|
-
* Note for both up/down and left/right explicitly set both enableLeftRight and enableUpDown to true.
|
23168
|
-
*/
|
23169
|
-
return function(settings) {
|
23170
|
-
var root = settings.root, enableUpDown = settings.enableUpDown !== false;
|
23171
|
-
var enableLeftRight = settings.enableLeftRight !== false;
|
23172
|
-
var items = settings.items, focussedId;
|
23173
|
-
|
23174
|
-
/**
|
23175
|
-
* Initializes the items array if needed. This will collect items/elements
|
23176
|
-
* from the specified root control.
|
23177
|
-
*/
|
23178
|
-
function initItems() {
|
23179
|
-
if (!items) {
|
23180
|
-
items = [];
|
23181
|
-
|
23182
|
-
if (root.find) {
|
23183
|
-
// Root is a container then get child elements using the UI API
|
23184
|
-
root.find('*').each(function(ctrl) {
|
23185
|
-
if (ctrl.canFocus) {
|
23186
|
-
items.push(ctrl.getEl());
|
23187
|
-
}
|
23188
|
-
});
|
23189
|
-
} else {
|
23190
|
-
// Root is a control/widget then get the child elements of that control
|
23191
|
-
var elements = root.getEl().getElementsByTagName('*');
|
23192
|
-
for (var i = 0; i < elements.length; i++) {
|
23193
|
-
if (elements[i].id && elements[i]) {
|
23194
|
-
items.push(elements[i]);
|
23195
|
-
}
|
23196
|
-
}
|
23197
|
-
}
|
23198
|
-
}
|
23199
|
-
}
|
23200
|
-
|
23201
|
-
/**
|
23202
|
-
* Returns the currently focused element.
|
23203
|
-
*
|
23204
|
-
* @private
|
23205
|
-
* @return {Element} Currently focused element.
|
23206
|
-
*/
|
23207
|
-
function getFocusElement() {
|
23208
|
-
return document.getElementById(focussedId);
|
23209
|
-
}
|
23210
|
-
|
23211
|
-
/**
|
23212
|
-
* Returns the currently focused elements wai aria role.
|
23213
|
-
*
|
23214
|
-
* @private
|
23215
|
-
* @param {Element} elm Optional element to get role from.
|
23216
|
-
* @return {String} Role of specified element.
|
23217
|
-
*/
|
23218
|
-
function getRole(elm) {
|
23219
|
-
elm = elm || getFocusElement();
|
23220
|
-
|
23221
|
-
return elm && elm.getAttribute('role');
|
23222
|
-
}
|
23223
|
-
|
23224
|
-
/**
|
23225
|
-
* Returns the role of the parent element.
|
23226
|
-
*
|
23227
|
-
* @private
|
23228
|
-
* @param {Element} elm Optional element to get parent role from.
|
23229
|
-
* @return {String} Role of the first parent that has a role.
|
23230
|
-
*/
|
23231
|
-
function getParentRole(elm) {
|
23232
|
-
var role, parent = elm || getFocusElement();
|
23233
|
-
|
23234
|
-
while ((parent = parent.parentNode)) {
|
23235
|
-
if ((role = getRole(parent))) {
|
23236
|
-
return role;
|
23237
|
-
}
|
23238
|
-
}
|
23239
|
-
}
|
23240
|
-
|
23241
|
-
/**
|
23242
|
-
* Returns an wai aria property by name.
|
23243
|
-
*
|
23244
|
-
* @private
|
23245
|
-
* @param {String} name Name of the aria property to get for example "disabled".
|
23246
|
-
* @return {String} Aria property value.
|
23247
|
-
*/
|
23248
|
-
function getAriaProp(name) {
|
23249
|
-
var elm = document.getElementById(focussedId);
|
23250
|
-
|
23251
|
-
if (elm) {
|
23252
|
-
return elm.getAttribute('aria-' + name);
|
23253
|
-
}
|
23254
|
-
}
|
23255
|
-
|
23256
|
-
/**
|
23257
|
-
* Executes the onAction event callback. This is when the user presses enter/space.
|
23258
|
-
*
|
23259
|
-
* @private
|
23260
|
-
*/
|
23261
|
-
function action() {
|
23262
|
-
var focusElm = getFocusElement();
|
23263
|
-
|
23264
|
-
if (focusElm && (focusElm.nodeName == "TEXTAREA" || focusElm.type == "text")) {
|
23265
|
-
return;
|
23266
|
-
}
|
23267
|
-
|
23268
|
-
if (settings.onAction) {
|
23269
|
-
settings.onAction(focussedId);
|
23270
|
-
} else {
|
23271
|
-
DomUtils.fire(getFocusElement(), 'click', {keyboard: true});
|
23272
|
-
}
|
23273
|
-
|
23274
|
-
return true;
|
23275
|
-
}
|
23276
|
-
|
23277
|
-
/**
|
23278
|
-
* Cancels the current navigation. The same as pressing the Esc key.
|
23279
|
-
*
|
23280
|
-
* @method cancel
|
23281
|
-
*/
|
23282
|
-
function cancel() {
|
23283
|
-
var focusElm;
|
23284
|
-
|
23285
|
-
if (settings.onCancel) {
|
23286
|
-
if ((focusElm = getFocusElement())) {
|
23287
|
-
focusElm.blur();
|
23288
|
-
}
|
23289
|
-
|
23290
|
-
settings.onCancel();
|
23291
|
-
} else {
|
23292
|
-
settings.root.fire('cancel');
|
23293
|
-
}
|
23294
|
-
}
|
23295
|
-
|
23296
|
-
/**
|
23297
|
-
* Moves the focus to the next or previous item. It will wrap to start/end if it can't move.
|
23298
|
-
*
|
23299
|
-
* @method moveFocus
|
23300
|
-
* @param {Number} dir Direction for move -1 or 1.
|
23301
|
-
*/
|
23302
|
-
function moveFocus(dir) {
|
23303
|
-
var idx = -1, focusElm, i;
|
23304
|
-
var visibleItems = [];
|
23305
|
-
|
23306
|
-
function isVisible(elm) {
|
23307
|
-
var rootElm = root ? root.getEl() : document.body;
|
23308
|
-
|
23309
|
-
while (elm && elm != rootElm) {
|
23310
|
-
if (elm.style.display == 'none') {
|
23311
|
-
return false;
|
23312
|
-
}
|
23313
|
-
|
23314
|
-
elm = elm.parentNode;
|
23315
|
-
}
|
23316
|
-
|
23317
|
-
return true;
|
23318
|
-
}
|
23319
|
-
|
23320
|
-
initItems();
|
23321
|
-
|
23322
|
-
// TODO: Optimize this, will be slow on lots of items
|
23323
|
-
i = visibleItems.length;
|
23324
|
-
for (i = 0; i < items.length; i++) {
|
23325
|
-
if (isVisible(items[i])) {
|
23326
|
-
visibleItems.push(items[i]);
|
23327
|
-
}
|
23328
|
-
}
|
23329
|
-
|
23330
|
-
i = visibleItems.length;
|
23331
|
-
while (i--) {
|
23332
|
-
if (visibleItems[i].id === focussedId) {
|
23333
|
-
idx = i;
|
23334
|
-
break;
|
23335
|
-
}
|
23336
|
-
}
|
23337
|
-
|
23338
|
-
idx += dir;
|
23339
|
-
if (idx < 0) {
|
23340
|
-
idx = visibleItems.length - 1;
|
23341
|
-
} else if (idx >= visibleItems.length) {
|
23342
|
-
idx = 0;
|
23343
|
-
}
|
23344
|
-
|
23345
|
-
focusElm = visibleItems[idx];
|
23346
|
-
focusElm.focus();
|
23347
|
-
focussedId = focusElm.id;
|
23348
|
-
|
23349
|
-
if (settings.actOnFocus) {
|
23350
|
-
action();
|
23351
|
-
}
|
23352
|
-
}
|
23353
|
-
|
23354
|
-
/**
|
23355
|
-
* Moves focus to the first item or the last focused item if root is a toolbar.
|
23356
|
-
*
|
23357
|
-
* @method focusFirst
|
23358
|
-
* @return {[type]} [description]
|
23359
|
-
*/
|
23360
|
-
function focusFirst() {
|
23361
|
-
var i, rootRole;
|
23362
|
-
|
23363
|
-
rootRole = getRole(settings.root.getEl());
|
23364
|
-
initItems();
|
23365
|
-
|
23366
|
-
i = items.length;
|
23367
|
-
while (i--) {
|
23368
|
-
if (rootRole == 'toolbar' && items[i].id === focussedId) {
|
23369
|
-
items[i].focus();
|
23370
|
-
return;
|
23371
|
-
}
|
23372
|
-
}
|
23373
|
-
|
23374
|
-
items[0].focus();
|
23375
|
-
}
|
23376
|
-
|
23377
|
-
// Handle accessible keys
|
23378
|
-
root.on('keydown', function(e) {
|
23379
|
-
var DOM_VK_LEFT = 37, DOM_VK_RIGHT = 39, DOM_VK_UP = 38, DOM_VK_DOWN = 40;
|
23380
|
-
var DOM_VK_ESCAPE = 27, DOM_VK_ENTER = 14, DOM_VK_RETURN = 13, DOM_VK_SPACE = 32, DOM_VK_TAB = 9;
|
23381
|
-
var preventDefault;
|
23382
|
-
|
23383
|
-
switch (e.keyCode) {
|
23384
|
-
case DOM_VK_LEFT:
|
23385
|
-
if (enableLeftRight) {
|
23386
|
-
if (settings.leftAction) {
|
23387
|
-
settings.leftAction();
|
23388
|
-
} else {
|
23389
|
-
moveFocus(-1);
|
23390
|
-
}
|
23391
|
-
|
23392
|
-
preventDefault = true;
|
23393
|
-
}
|
23394
|
-
break;
|
23395
|
-
|
23396
|
-
case DOM_VK_RIGHT:
|
23397
|
-
if (enableLeftRight) {
|
23398
|
-
if (getRole() == 'menuitem' && getParentRole() == 'menu') {
|
23399
|
-
if (getAriaProp('haspopup')) {
|
23400
|
-
action();
|
23401
|
-
}
|
23402
|
-
} else {
|
23403
|
-
moveFocus(1);
|
23404
|
-
}
|
23405
|
-
|
23406
|
-
preventDefault = true;
|
23407
|
-
}
|
23408
|
-
break;
|
23409
|
-
|
23410
|
-
case DOM_VK_UP:
|
23411
|
-
if (enableUpDown) {
|
23412
|
-
moveFocus(-1);
|
23413
|
-
preventDefault = true;
|
23414
|
-
}
|
23415
|
-
break;
|
23416
|
-
|
23417
|
-
case DOM_VK_DOWN:
|
23418
|
-
if (enableUpDown) {
|
23419
|
-
if (getRole() == 'menuitem' && getParentRole() == 'menubar') {
|
23420
|
-
action();
|
23421
|
-
} else if (getRole() == 'button' && getAriaProp('haspopup')) {
|
23422
|
-
action();
|
23423
|
-
} else {
|
23424
|
-
moveFocus(1);
|
23425
|
-
}
|
23426
|
-
|
23427
|
-
preventDefault = true;
|
23428
|
-
}
|
23429
|
-
break;
|
23430
|
-
|
23431
|
-
case DOM_VK_TAB:
|
23432
|
-
preventDefault = true;
|
23433
|
-
|
23434
|
-
if (e.shiftKey) {
|
23435
|
-
moveFocus(-1);
|
23436
|
-
} else {
|
23437
|
-
moveFocus(1);
|
23438
|
-
}
|
23439
|
-
break;
|
23440
|
-
|
23441
|
-
case DOM_VK_ESCAPE:
|
23442
|
-
preventDefault = true;
|
23443
|
-
cancel();
|
23444
|
-
break;
|
23445
|
-
|
23446
|
-
case DOM_VK_ENTER:
|
23447
|
-
case DOM_VK_RETURN:
|
23448
|
-
case DOM_VK_SPACE:
|
23449
|
-
preventDefault = action();
|
23450
|
-
break;
|
23451
|
-
}
|
23452
|
-
|
23453
|
-
if (preventDefault) {
|
23454
|
-
e.stopPropagation();
|
23455
|
-
e.preventDefault();
|
23456
|
-
}
|
23457
|
-
});
|
23458
|
-
|
23459
|
-
// Init on focus in
|
23460
|
-
root.on('focusin', function(e) {
|
23461
|
-
initItems();
|
23462
|
-
focussedId = e.target.id;
|
23463
|
-
});
|
23464
|
-
|
23465
|
-
return {
|
23466
|
-
moveFocus: moveFocus,
|
23467
|
-
focusFirst: focusFirst,
|
23468
|
-
cancel: cancel
|
23469
|
-
};
|
23470
|
-
};
|
23471
|
-
});
|
23472
|
-
|
23473
23617
|
// Included from: js/tinymce/classes/ui/Window.js
|
23474
23618
|
|
23475
23619
|
/**
|
@@ -23493,9 +23637,8 @@ define("tinymce/ui/Window", [
|
|
23493
23637
|
"tinymce/ui/FloatPanel",
|
23494
23638
|
"tinymce/ui/Panel",
|
23495
23639
|
"tinymce/ui/DomUtils",
|
23496
|
-
"tinymce/ui/KeyboardNavigation",
|
23497
23640
|
"tinymce/ui/DragHelper"
|
23498
|
-
], function(FloatPanel, Panel, DomUtils,
|
23641
|
+
], function(FloatPanel, Panel, DomUtils, DragHelper) {
|
23499
23642
|
"use strict";
|
23500
23643
|
|
23501
23644
|
var Window = FloatPanel.extend({
|
@@ -23560,6 +23703,11 @@ define("tinymce/ui/Window", [
|
|
23560
23703
|
}
|
23561
23704
|
});
|
23562
23705
|
|
23706
|
+
self.on('cancel', function() {
|
23707
|
+
self.close();
|
23708
|
+
});
|
23709
|
+
|
23710
|
+
self.aria('describedby', self.describedBy || self._id + '-none');
|
23563
23711
|
self.aria('label', settings.title);
|
23564
23712
|
self._fullscreen = false;
|
23565
23713
|
},
|
@@ -23667,7 +23815,7 @@ define("tinymce/ui/Window", [
|
|
23667
23815
|
if (settings.title) {
|
23668
23816
|
headerHtml = (
|
23669
23817
|
'<div id="' + id + '-head" class="' + prefix + 'window-head">' +
|
23670
|
-
'<div class="' + prefix + 'title">' + self.encode(settings.title) + '</div>' +
|
23818
|
+
'<div id="' + id + '-title" class="' + prefix + 'title">' + self.encode(settings.title) + '</div>' +
|
23671
23819
|
'<button type="button" class="' + prefix + 'close" aria-hidden="true">×</button>' +
|
23672
23820
|
'<div id="' + id + '-dragh" class="' + prefix + 'dragh"></div>' +
|
23673
23821
|
'</div>'
|
@@ -23687,12 +23835,14 @@ define("tinymce/ui/Window", [
|
|
23687
23835
|
}
|
23688
23836
|
|
23689
23837
|
return (
|
23690
|
-
'<div id="' + id + '" class="' + self.classes() + '" hideFocus="1"
|
23691
|
-
|
23692
|
-
|
23693
|
-
|
23838
|
+
'<div id="' + id + '" class="' + self.classes() + '" hideFocus="1">' +
|
23839
|
+
'<div class="' + self.classPrefix + 'reset" role="application">' +
|
23840
|
+
headerHtml +
|
23841
|
+
'<div id="' + id + '-body" class="' + self.classes('body') + '">' +
|
23842
|
+
html +
|
23843
|
+
'</div>' +
|
23844
|
+
footerHtml +
|
23694
23845
|
'</div>' +
|
23695
|
-
footerHtml +
|
23696
23846
|
'</div>'
|
23697
23847
|
);
|
23698
23848
|
},
|
@@ -23770,59 +23920,19 @@ define("tinymce/ui/Window", [
|
|
23770
23920
|
* @method postRender
|
23771
23921
|
*/
|
23772
23922
|
postRender: function() {
|
23773
|
-
var self = this,
|
23923
|
+
var self = this, startPos;
|
23774
23924
|
|
23775
23925
|
setTimeout(function() {
|
23776
23926
|
self.addClass('in');
|
23777
23927
|
}, 0);
|
23778
23928
|
|
23779
|
-
self.keyboardNavigation = new KeyboardNavigation({
|
23780
|
-
root: self,
|
23781
|
-
enableLeftRight: false,
|
23782
|
-
enableUpDown: false,
|
23783
|
-
items: items,
|
23784
|
-
onCancel: function() {
|
23785
|
-
self.close();
|
23786
|
-
}
|
23787
|
-
});
|
23788
|
-
|
23789
|
-
self.find('*').each(function(ctrl) {
|
23790
|
-
if (ctrl.canFocus) {
|
23791
|
-
autoFocusFound = autoFocusFound || ctrl.settings.autofocus;
|
23792
|
-
focusCtrl = focusCtrl || ctrl;
|
23793
|
-
|
23794
|
-
// TODO: Figure out a better way
|
23795
|
-
if (ctrl.subinput) {
|
23796
|
-
items.push(ctrl.getEl('inp'));
|
23797
|
-
|
23798
|
-
if (ctrl.getEl('open')) {
|
23799
|
-
items.push(ctrl.getEl('open'));
|
23800
|
-
}
|
23801
|
-
} else {
|
23802
|
-
items.push(ctrl.getEl());
|
23803
|
-
}
|
23804
|
-
}
|
23805
|
-
});
|
23806
|
-
|
23807
|
-
if (self.statusbar) {
|
23808
|
-
self.statusbar.find('*').each(function(ctrl) {
|
23809
|
-
if (ctrl.canFocus) {
|
23810
|
-
autoFocusFound = autoFocusFound || ctrl.settings.autofocus;
|
23811
|
-
focusCtrl = focusCtrl || ctrl;
|
23812
|
-
items.push(ctrl.getEl());
|
23813
|
-
}
|
23814
|
-
});
|
23815
|
-
}
|
23816
|
-
|
23817
23929
|
self._super();
|
23818
23930
|
|
23819
23931
|
if (self.statusbar) {
|
23820
23932
|
self.statusbar.postRender();
|
23821
23933
|
}
|
23822
23934
|
|
23823
|
-
|
23824
|
-
focusCtrl.focus();
|
23825
|
-
}
|
23935
|
+
self.focus();
|
23826
23936
|
|
23827
23937
|
this.dragHelper = new DragHelper(self._id + '-dragh', {
|
23828
23938
|
start: function() {
|
@@ -24031,6 +24141,7 @@ define("tinymce/ui/MessageBox", [
|
|
24031
24141
|
align: "center",
|
24032
24142
|
buttons: buttons,
|
24033
24143
|
title: settings.title,
|
24144
|
+
role: 'alertdialog',
|
24034
24145
|
items: {
|
24035
24146
|
type: "label",
|
24036
24147
|
multiline: true,
|
@@ -24038,7 +24149,13 @@ define("tinymce/ui/MessageBox", [
|
|
24038
24149
|
maxHeight: 200,
|
24039
24150
|
text: settings.text
|
24040
24151
|
},
|
24041
|
-
|
24152
|
+
onPostRender: function() {
|
24153
|
+
this.aria('describedby', this.items()[0]._id);
|
24154
|
+
},
|
24155
|
+
onClose: settings.onClose,
|
24156
|
+
onCancel: function() {
|
24157
|
+
callback(false);
|
24158
|
+
}
|
24042
24159
|
}).renderTo(document.body).reflow();
|
24043
24160
|
},
|
24044
24161
|
|
@@ -24145,7 +24262,7 @@ define("tinymce/WindowManager", [
|
|
24145
24262
|
* @option {Number} height Height in pixels.
|
24146
24263
|
* @option {Boolean} resizable Specifies whether the popup window is resizable or not.
|
24147
24264
|
* @option {Boolean} maximizable Specifies whether the popup window has a "maximize" button and can get maximized or not.
|
24148
|
-
* @option {String/
|
24265
|
+
* @option {String/Boolean} scrollbars Specifies whether the popup window can have scrollbars if required (i.e. content
|
24149
24266
|
* larger than the popup size specified).
|
24150
24267
|
*/
|
24151
24268
|
self.open = function(args, params) {
|
@@ -24238,6 +24355,8 @@ define("tinymce/WindowManager", [
|
|
24238
24355
|
MessageBox.alert(message, function() {
|
24239
24356
|
if (callback) {
|
24240
24357
|
callback.call(scope || this);
|
24358
|
+
} else {
|
24359
|
+
editor.focus();
|
24241
24360
|
}
|
24242
24361
|
});
|
24243
24362
|
};
|
@@ -24850,8 +24969,8 @@ define("tinymce/util/Quirks", [
|
|
24850
24969
|
return;
|
24851
24970
|
}
|
24852
24971
|
|
24853
|
-
|
24854
|
-
|
24972
|
+
// Enable display: none in area and add a specific class that hides all BR elements in PRE to
|
24973
|
+
// avoid the caret from getting stuck at the BR elements while pressing the right arrow key
|
24855
24974
|
setEditorCommandState('RespectVisibilityInDesign', true);
|
24856
24975
|
editor.contentStyles.push('.mceHideBrInPre pre br {display: none}');
|
24857
24976
|
dom.addClass(editor.getBody(), 'mceHideBrInPre');
|
@@ -25208,7 +25327,7 @@ define("tinymce/util/Quirks", [
|
|
25208
25327
|
dom.bind(doc, 'mouseup', endSelection);
|
25209
25328
|
dom.bind(doc, 'mousemove', selectionChange);
|
25210
25329
|
|
25211
|
-
dom.
|
25330
|
+
dom.getRoot().focus();
|
25212
25331
|
startRng.select();
|
25213
25332
|
}
|
25214
25333
|
}
|
@@ -25272,8 +25391,8 @@ define("tinymce/util/Quirks", [
|
|
25272
25391
|
editor.contentStyles.push('body {min-height: 150px}');
|
25273
25392
|
editor.on('click', function(e) {
|
25274
25393
|
if (e.target.nodeName == 'HTML') {
|
25275
|
-
editor.
|
25276
|
-
editor.selection.
|
25394
|
+
editor.getBody().focus();
|
25395
|
+
editor.selection.normalize();
|
25277
25396
|
editor.nodeChanged();
|
25278
25397
|
}
|
25279
25398
|
});
|
@@ -25302,6 +25421,21 @@ define("tinymce/util/Quirks", [
|
|
25302
25421
|
setEditorCommandState("AutoUrlDetect", false);
|
25303
25422
|
}
|
25304
25423
|
|
25424
|
+
/**
|
25425
|
+
* IE 11 has a fantastic bug where it will produce two trailing BR elements to iframe bodies when
|
25426
|
+
* the iframe is hidden by display: none. This workaround solves this by switching
|
25427
|
+
* on designMode on the whole document.
|
25428
|
+
*
|
25429
|
+
* Example this: <body>text</body> becomes <body>text<br><br></body>
|
25430
|
+
*/
|
25431
|
+
function doubleTrailingBrElements() {
|
25432
|
+
if (!editor.inline) {
|
25433
|
+
editor.on('init', function() {
|
25434
|
+
editor.getDoc().designMode = 'on';
|
25435
|
+
});
|
25436
|
+
}
|
25437
|
+
}
|
25438
|
+
|
25305
25439
|
// All browsers
|
25306
25440
|
disableBackspaceIntoATable();
|
25307
25441
|
removeBlockQuoteOnBackSpace();
|
@@ -25339,6 +25473,7 @@ define("tinymce/util/Quirks", [
|
|
25339
25473
|
|
25340
25474
|
if (Env.ie >= 11) {
|
25341
25475
|
bodyHeight();
|
25476
|
+
doubleTrailingBrElements();
|
25342
25477
|
}
|
25343
25478
|
|
25344
25479
|
if (Env.ie) {
|
@@ -26984,7 +27119,7 @@ define("tinymce/Editor", [
|
|
26984
27119
|
*
|
26985
27120
|
* setup: function(ed) {
|
26986
27121
|
* ed.addMenuItem('example', {
|
26987
|
-
*
|
27122
|
+
* text: 'My menu item',
|
26988
27123
|
* context: 'tools',
|
26989
27124
|
* onclick: function() {
|
26990
27125
|
* ed.insertContent('Hello world!!');
|
@@ -27359,7 +27494,10 @@ define("tinymce/Editor", [
|
|
27359
27494
|
html = args.content;
|
27360
27495
|
|
27361
27496
|
if (!/TEXTAREA|INPUT/i.test(elm.nodeName)) {
|
27362
|
-
|
27497
|
+
// Update DIV element when not in inline mode
|
27498
|
+
if (!self.inline) {
|
27499
|
+
elm.innerHTML = html;
|
27500
|
+
}
|
27363
27501
|
|
27364
27502
|
// Update hidden form element
|
27365
27503
|
if ((form = DOM.getParent(self.id, 'form'))) {
|
@@ -27702,7 +27840,7 @@ define("tinymce/Editor", [
|
|
27702
27840
|
case 'A':
|
27703
27841
|
if (!dom.getAttrib(elm, 'href', false)) {
|
27704
27842
|
value = dom.getAttrib(elm, 'name') || elm.id;
|
27705
|
-
cls = 'mce-item-anchor';
|
27843
|
+
cls = settings.visual_anchor_class || 'mce-item-anchor';
|
27706
27844
|
|
27707
27845
|
if (value) {
|
27708
27846
|
if (self.hasVisual) {
|
@@ -27921,7 +28059,7 @@ define("tinymce/util/I18n", [], function() {
|
|
27921
28059
|
* Property gets set to true if a RTL language pack was loaded.
|
27922
28060
|
*
|
27923
28061
|
* @property rtl
|
27924
|
-
* @type
|
28062
|
+
* @type Boolean
|
27925
28063
|
*/
|
27926
28064
|
rtl: false,
|
27927
28065
|
|
@@ -28069,14 +28207,24 @@ define("tinymce/FocusManager", [
|
|
28069
28207
|
editor.on('init', function() {
|
28070
28208
|
// On IE take selection snapshot onbeforedeactivate
|
28071
28209
|
if ("onbeforedeactivate" in document && Env.ie < 11) {
|
28210
|
+
// Gets fired when the editor is about to be blurred but also when the selection
|
28211
|
+
// is moved into a table cell so we need to add the range as a pending range then
|
28212
|
+
// use that pending range on the blur event of the editor body
|
28072
28213
|
editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
|
28073
28214
|
try {
|
28074
|
-
editor.
|
28215
|
+
editor.pendingRng = editor.selection.getRng();
|
28075
28216
|
} catch (ex) {
|
28076
28217
|
// IE throws "Unexcpected call to method or property access" some times so lets ignore it
|
28077
28218
|
}
|
28219
|
+
});
|
28078
28220
|
|
28079
|
-
|
28221
|
+
// Set the pending range as the current last range if the blur event occurs
|
28222
|
+
editor.dom.bind(editor.getBody(), 'blur', function() {
|
28223
|
+
if (editor.pendingRng) {
|
28224
|
+
editor.lastRng = editor.pendingRng;
|
28225
|
+
editor.selection.lastFocusBookmark = createBookmark(editor.lastRng);
|
28226
|
+
editor.pendingRng = null;
|
28227
|
+
}
|
28080
28228
|
});
|
28081
28229
|
} else if (editor.inline || Env.ie > 10) {
|
28082
28230
|
// On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
|
@@ -28142,7 +28290,7 @@ define("tinymce/FocusManager", [
|
|
28142
28290
|
editorManager.activeEditor = editor;
|
28143
28291
|
editorManager.focusedEditor = editor;
|
28144
28292
|
editor.fire('focus', {blurredEditor: focusedEditor});
|
28145
|
-
editor.focus(
|
28293
|
+
editor.focus(true);
|
28146
28294
|
}
|
28147
28295
|
|
28148
28296
|
editor.lastRng = null;
|
@@ -28172,7 +28320,6 @@ define("tinymce/FocusManager", [
|
|
28172
28320
|
var activeEditor = editorManager.activeEditor;
|
28173
28321
|
|
28174
28322
|
if (activeEditor && e.target.ownerDocument == document) {
|
28175
|
-
|
28176
28323
|
// Check to make sure we have a valid selection
|
28177
28324
|
if (activeEditor.selection) {
|
28178
28325
|
activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.lastRng);
|
@@ -28254,7 +28401,7 @@ define("tinymce/EditorManager", [
|
|
28254
28401
|
* @property minorVersion
|
28255
28402
|
* @type String
|
28256
28403
|
*/
|
28257
|
-
minorVersion : '0.
|
28404
|
+
minorVersion : '0.18',
|
28258
28405
|
|
28259
28406
|
/**
|
28260
28407
|
* Release date of TinyMCE build.
|
@@ -28262,7 +28409,7 @@ define("tinymce/EditorManager", [
|
|
28262
28409
|
* @property releaseDate
|
28263
28410
|
* @type String
|
28264
28411
|
*/
|
28265
|
-
releaseDate: '2014-
|
28412
|
+
releaseDate: '2014-02-27',
|
28266
28413
|
|
28267
28414
|
/**
|
28268
28415
|
* Collection of editor instances.
|
@@ -29846,10 +29993,9 @@ define("tinymce/ui/Widget", [
|
|
29846
29993
|
self.on('mouseleave mousedown click', function() {
|
29847
29994
|
self.tooltip().hide();
|
29848
29995
|
});
|
29849
|
-
|
29850
29996
|
}
|
29851
29997
|
|
29852
|
-
self.aria('label', settings.tooltip);
|
29998
|
+
self.aria('label', settings.ariaLabel || settings.tooltip);
|
29853
29999
|
},
|
29854
30000
|
|
29855
30001
|
/**
|
@@ -29859,11 +30005,9 @@ define("tinymce/ui/Widget", [
|
|
29859
30005
|
* @return {tinymce.ui.Tooltip} Tooltip instance.
|
29860
30006
|
*/
|
29861
30007
|
tooltip: function() {
|
29862
|
-
var self = this;
|
29863
|
-
|
29864
30008
|
if (!tooltip) {
|
29865
30009
|
tooltip = new Tooltip({type: 'tooltip'});
|
29866
|
-
tooltip.renderTo(
|
30010
|
+
tooltip.renderTo();
|
29867
30011
|
}
|
29868
30012
|
|
29869
30013
|
return tooltip;
|
@@ -29923,9 +30067,7 @@ define("tinymce/ui/Widget", [
|
|
29923
30067
|
}
|
29924
30068
|
|
29925
30069
|
if (settings.autofocus) {
|
29926
|
-
|
29927
|
-
self.focus();
|
29928
|
-
}, 0);
|
30070
|
+
self.focus();
|
29929
30071
|
}
|
29930
30072
|
},
|
29931
30073
|
|
@@ -30081,7 +30223,7 @@ define("tinymce/ui/Button", [
|
|
30081
30223
|
icon = self.settings.icon ? prefix + 'ico ' + prefix + 'i-' + icon : '';
|
30082
30224
|
|
30083
30225
|
return (
|
30084
|
-
'<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
|
30226
|
+
'<div id="' + id + '" class="' + self.classes() + '" tabindex="-1" aria-labelledby="' + id + '">' +
|
30085
30227
|
'<button role="presentation" type="button" tabindex="-1">' +
|
30086
30228
|
(icon ? '<i class="' + icon + '"' + image + '></i>' : '') +
|
30087
30229
|
(self._text ? (icon ? '\u00a0' : '') + self.encode(self._text) : '') +
|
@@ -30130,7 +30272,7 @@ define("tinymce/ui/ButtonGroup", [
|
|
30130
30272
|
return Container.extend({
|
30131
30273
|
Defaults: {
|
30132
30274
|
defaultType: 'button',
|
30133
|
-
role: '
|
30275
|
+
role: 'group'
|
30134
30276
|
},
|
30135
30277
|
|
30136
30278
|
/**
|
@@ -30326,12 +30468,19 @@ define("tinymce/ui/PanelButton", [
|
|
30326
30468
|
};
|
30327
30469
|
}
|
30328
30470
|
|
30471
|
+
panelSettings.role = panelSettings.role || 'dialog';
|
30329
30472
|
panelSettings.popover = true;
|
30330
30473
|
panelSettings.autohide = true;
|
30474
|
+
panelSettings.ariaRoot = true;
|
30331
30475
|
|
30332
30476
|
self.panel = new FloatPanel(panelSettings).on('hide', function() {
|
30333
30477
|
self.active(false);
|
30478
|
+
}).on('cancel', function(e) {
|
30479
|
+
e.stopPropagation();
|
30480
|
+
self.focus();
|
30481
|
+
self.hidePanel();
|
30334
30482
|
}).parent(self).renderTo(self.getContainerElm());
|
30483
|
+
|
30335
30484
|
self.panel.fire('show');
|
30336
30485
|
self.panel.reflow();
|
30337
30486
|
} else {
|
@@ -30362,12 +30511,15 @@ define("tinymce/ui/PanelButton", [
|
|
30362
30511
|
postRender: function() {
|
30363
30512
|
var self = this;
|
30364
30513
|
|
30514
|
+
self.aria('haspopup', true);
|
30515
|
+
|
30365
30516
|
self.on('click', function(e) {
|
30366
30517
|
if (e.control === self) {
|
30367
30518
|
if (self.panel && self.panel.visible()) {
|
30368
30519
|
self.hidePanel();
|
30369
30520
|
} else {
|
30370
30521
|
self.showPanel();
|
30522
|
+
self.panel.focus(!!e.aria);
|
30371
30523
|
}
|
30372
30524
|
}
|
30373
30525
|
});
|
@@ -30447,7 +30599,7 @@ define("tinymce/ui/ColorButton", [
|
|
30447
30599
|
var image = self.settings.image ? ' style="background-image: url(\'' + self.settings.image + '\')"' : '';
|
30448
30600
|
|
30449
30601
|
return (
|
30450
|
-
'<div id="' + id + '" class="' + self.classes() + '">' +
|
30602
|
+
'<div id="' + id + '" class="' + self.classes() + '" role="button" tabindex="-1" aria-haspopup="true">' +
|
30451
30603
|
'<button role="presentation" hidefocus type="button" tabindex="-1">' +
|
30452
30604
|
(icon ? '<i class="' + icon + '"' + image + '></i>' : '') +
|
30453
30605
|
'<span id="' + id + '-preview" class="' + prefix + 'preview"></span>' +
|
@@ -30469,6 +30621,10 @@ define("tinymce/ui/ColorButton", [
|
|
30469
30621
|
var self = this, onClickHandler = self.settings.onclick;
|
30470
30622
|
|
30471
30623
|
self.on('click', function(e) {
|
30624
|
+
if (e.aria && e.aria.key == 'down') {
|
30625
|
+
return;
|
30626
|
+
}
|
30627
|
+
|
30472
30628
|
if (e.control == self && !DOM.getParent(e.target, '.' + self.classPrefix + 'open')) {
|
30473
30629
|
e.stopImmediatePropagation();
|
30474
30630
|
onClickHandler.call(self, e);
|
@@ -30524,6 +30680,7 @@ define("tinymce/ui/ComboBox", [
|
|
30524
30680
|
self._super(settings);
|
30525
30681
|
self.addClass('combobox');
|
30526
30682
|
self.subinput = true;
|
30683
|
+
self.ariaTarget = 'inp'; // TODO: Figure out a better way
|
30527
30684
|
|
30528
30685
|
settings = self.settings;
|
30529
30686
|
settings.menu = settings.menu || settings.values;
|
@@ -30533,16 +30690,16 @@ define("tinymce/ui/ComboBox", [
|
|
30533
30690
|
}
|
30534
30691
|
|
30535
30692
|
self.on('click', function(e) {
|
30536
|
-
var elm = e.target;
|
30693
|
+
var elm = e.target, root = self.getEl();
|
30537
30694
|
|
30538
|
-
while (elm) {
|
30695
|
+
while (elm && elm != root) {
|
30539
30696
|
if (elm.id && elm.id.indexOf('-open') != -1) {
|
30540
30697
|
self.fire('action');
|
30541
30698
|
|
30542
30699
|
if (settings.menu) {
|
30543
30700
|
self.showMenu();
|
30544
30701
|
|
30545
|
-
if (e.
|
30702
|
+
if (e.aria) {
|
30546
30703
|
self.menu.items()[0].focus();
|
30547
30704
|
}
|
30548
30705
|
}
|
@@ -30795,7 +30952,7 @@ define("tinymce/ui/ComboBox", [
|
|
30795
30952
|
|
30796
30953
|
if (icon || text) {
|
30797
30954
|
openBtnHtml = (
|
30798
|
-
'<div id="' + id + '-open" class="' + prefix + 'btn ' + prefix + 'open" tabIndex="-1">' +
|
30955
|
+
'<div id="' + id + '-open" class="' + prefix + 'btn ' + prefix + 'open" tabIndex="-1" role="button">' +
|
30799
30956
|
'<button id="' + id + '-action" type="button" hidefocus tabindex="-1">' +
|
30800
30957
|
(icon != 'caret' ? '<i class="' + icon + '"></i>' : '<i class="' + prefix + 'caret"></i>') +
|
30801
30958
|
(text ? (icon ? ' ' : '') + text : '') +
|
@@ -30837,9 +30994,8 @@ define("tinymce/ui/ComboBox", [
|
|
30837
30994
|
* @extends tinymce.ui.Widget
|
30838
30995
|
*/
|
30839
30996
|
define("tinymce/ui/Path", [
|
30840
|
-
"tinymce/ui/Widget"
|
30841
|
-
|
30842
|
-
], function(Widget, KeyboardNavigation) {
|
30997
|
+
"tinymce/ui/Widget"
|
30998
|
+
], function(Widget) {
|
30843
30999
|
"use strict";
|
30844
31000
|
|
30845
31001
|
return Widget.extend({
|
@@ -30879,12 +31035,7 @@ define("tinymce/ui/Path", [
|
|
30879
31035
|
focus: function() {
|
30880
31036
|
var self = this;
|
30881
31037
|
|
30882
|
-
self.
|
30883
|
-
root: self,
|
30884
|
-
enableLeftRight: true
|
30885
|
-
});
|
30886
|
-
|
30887
|
-
self.keyNav.focusFirst();
|
31038
|
+
self.getEl().firstChild.focus();
|
30888
31039
|
|
30889
31040
|
return self;
|
30890
31041
|
},
|
@@ -30953,7 +31104,7 @@ define("tinymce/ui/Path", [
|
|
30953
31104
|
html += (
|
30954
31105
|
(i > 0 ? '<div class="'+ prefix + 'divider" aria-hidden="true"> ' + self.settings.delimiter + ' </div>' : '') +
|
30955
31106
|
'<div role="button" class="' + prefix + 'path-item' + (i == l - 1 ? ' ' + prefix + 'last' : '') + '" data-index="' +
|
30956
|
-
i + '" tabindex="-1" id="' + self._id + '-' + i +'">' + parts[i].name + '</div>'
|
31107
|
+
i + '" tabindex="-1" id="' + self._id + '-' + i +'" aria-level="' + i + '">' + parts[i].name + '</div>'
|
30957
31108
|
);
|
30958
31109
|
}
|
30959
31110
|
|
@@ -31181,11 +31332,12 @@ define("tinymce/ui/Form", [
|
|
31181
31332
|
autoResize: "overflow",
|
31182
31333
|
defaults: {flex: 1},
|
31183
31334
|
items: [
|
31184
|
-
{type: 'label', text: label, flex: 0, forId: ctrl._id, disabled: ctrl.disabled()}
|
31335
|
+
{type: 'label', id: ctrl._id + '-l', text: label, flex: 0, forId: ctrl._id, disabled: ctrl.disabled()}
|
31185
31336
|
]
|
31186
31337
|
});
|
31187
31338
|
|
31188
31339
|
formItem.type = 'formitem';
|
31340
|
+
ctrl.aria('labelledby', ctrl._id + '-l');
|
31189
31341
|
|
31190
31342
|
if (typeof(ctrl.settings.flex) == "undefined") {
|
31191
31343
|
ctrl.settings.flex = 1;
|
@@ -32852,9 +33004,8 @@ define("tinymce/ui/Label", [
|
|
32852
33004
|
* @extends tinymce.ui.Container
|
32853
33005
|
*/
|
32854
33006
|
define("tinymce/ui/Toolbar", [
|
32855
|
-
"tinymce/ui/Container"
|
32856
|
-
|
32857
|
-
], function(Container, KeyboardNavigation) {
|
33007
|
+
"tinymce/ui/Container"
|
33008
|
+
], function(Container) {
|
32858
33009
|
"use strict";
|
32859
33010
|
|
32860
33011
|
return Container.extend({
|
@@ -32886,11 +33037,6 @@ define("tinymce/ui/Toolbar", [
|
|
32886
33037
|
|
32887
33038
|
self.items().addClass('toolbar-item');
|
32888
33039
|
|
32889
|
-
self.keyNav = new KeyboardNavigation({
|
32890
|
-
root: self,
|
32891
|
-
enableLeftRight: true
|
32892
|
-
});
|
32893
|
-
|
32894
33040
|
return self._super();
|
32895
33041
|
}
|
32896
33042
|
});
|
@@ -32924,6 +33070,7 @@ define("tinymce/ui/MenuBar", [
|
|
32924
33070
|
Defaults: {
|
32925
33071
|
role: 'menubar',
|
32926
33072
|
containerCls: 'menubar',
|
33073
|
+
ariaRoot: true,
|
32927
33074
|
defaults: {
|
32928
33075
|
type: 'menubutton'
|
32929
33076
|
}
|
@@ -33018,22 +33165,29 @@ define("tinymce/ui/MenuButton", [
|
|
33018
33165
|
menu.type = menu.type || 'menu';
|
33019
33166
|
}
|
33020
33167
|
|
33021
|
-
self.menu = Factory.create(menu).parent(self).renderTo(
|
33168
|
+
self.menu = Factory.create(menu).parent(self).renderTo();
|
33022
33169
|
self.fire('createmenu');
|
33023
33170
|
self.menu.reflow();
|
33024
33171
|
self.menu.on('cancel', function(e) {
|
33025
|
-
if (e.control === self.menu) {
|
33172
|
+
if (e.control.parent() === self.menu) {
|
33173
|
+
e.stopPropagation();
|
33026
33174
|
self.focus();
|
33175
|
+
self.hideMenu();
|
33027
33176
|
}
|
33028
33177
|
});
|
33029
33178
|
|
33179
|
+
// Move focus to button when a menu item is selected/clicked
|
33180
|
+
self.menu.on('select', function() {
|
33181
|
+
self.focus();
|
33182
|
+
});
|
33183
|
+
|
33030
33184
|
self.menu.on('show hide', function(e) {
|
33031
33185
|
if (e.control == self.menu) {
|
33032
33186
|
self.activeMenu(e.type == 'show');
|
33033
33187
|
}
|
33034
|
-
}).fire('show');
|
33035
33188
|
|
33036
|
-
|
33189
|
+
self.aria('expanded', e.type == 'show');
|
33190
|
+
}).fire('show');
|
33037
33191
|
}
|
33038
33192
|
|
33039
33193
|
self.menu.show();
|
@@ -33057,7 +33211,6 @@ define("tinymce/ui/MenuButton", [
|
|
33057
33211
|
});
|
33058
33212
|
|
33059
33213
|
self.menu.hide();
|
33060
|
-
self.aria('expanded', false);
|
33061
33214
|
}
|
33062
33215
|
},
|
33063
33216
|
|
@@ -33083,7 +33236,7 @@ define("tinymce/ui/MenuButton", [
|
|
33083
33236
|
self.aria('role', self.parent() instanceof MenuBar ? 'menuitem' : 'button');
|
33084
33237
|
|
33085
33238
|
return (
|
33086
|
-
'<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
|
33239
|
+
'<div id="' + id + '" class="' + self.classes() + '" tabindex="-1" aria-labelledby="' + id + '">' +
|
33087
33240
|
'<button id="' + id + '-open" role="presentation" type="button" tabindex="-1">' +
|
33088
33241
|
(icon ? '<i class="' + icon + '"></i>' : '') +
|
33089
33242
|
'<span>' + (self._text ? (icon ? '\u00a0' : '') + self.encode(self._text) : '') + '</span>' +
|
@@ -33105,7 +33258,7 @@ define("tinymce/ui/MenuButton", [
|
|
33105
33258
|
if (e.control === self && isChildOf(e.target, self.getEl())) {
|
33106
33259
|
self.showMenu();
|
33107
33260
|
|
33108
|
-
if (e.
|
33261
|
+
if (e.aria) {
|
33109
33262
|
self.menu.items()[0].focus();
|
33110
33263
|
}
|
33111
33264
|
}
|
@@ -33215,9 +33368,16 @@ define("tinymce/ui/ListBox", [
|
|
33215
33368
|
if (selected) {
|
33216
33369
|
selectedText = selectedText || values[i].text;
|
33217
33370
|
self._value = values[i].value;
|
33371
|
+
break;
|
33218
33372
|
}
|
33219
33373
|
}
|
33220
33374
|
|
33375
|
+
// Default with first item
|
33376
|
+
if (!selected && values.length > 0) {
|
33377
|
+
selectedText = values[0].text;
|
33378
|
+
self._value = values[0].value;
|
33379
|
+
}
|
33380
|
+
|
33221
33381
|
settings.menu = values;
|
33222
33382
|
}
|
33223
33383
|
|
@@ -33356,13 +33516,11 @@ define("tinymce/ui/MenuItem", [
|
|
33356
33516
|
if (self._text === '-' || self._text === '|') {
|
33357
33517
|
self.addClass('menu-item-sep');
|
33358
33518
|
self.aria('role', 'separator');
|
33359
|
-
self.canFocus = false;
|
33360
33519
|
self._text = '-';
|
33361
33520
|
}
|
33362
33521
|
|
33363
33522
|
if (settings.selectable) {
|
33364
33523
|
self.aria('role', 'menuitemcheckbox');
|
33365
|
-
self.aria('checked', true);
|
33366
33524
|
self.addClass('menu-item-checkbox');
|
33367
33525
|
settings.icon = 'selected';
|
33368
33526
|
}
|
@@ -33375,24 +33533,6 @@ define("tinymce/ui/MenuItem", [
|
|
33375
33533
|
e.preventDefault();
|
33376
33534
|
});
|
33377
33535
|
|
33378
|
-
self.on('mouseenter click', function(e) {
|
33379
|
-
if (e.control === self) {
|
33380
|
-
if (!settings.menu && e.type === 'click') {
|
33381
|
-
self.parent().hideAll();
|
33382
|
-
self.fire('cancel');
|
33383
|
-
self.fire('select');
|
33384
|
-
} else {
|
33385
|
-
self.showMenu();
|
33386
|
-
|
33387
|
-
if (e.keyboard) {
|
33388
|
-
setTimeout(function() {
|
33389
|
-
self.menu.items()[0].focus();
|
33390
|
-
}, 0);
|
33391
|
-
}
|
33392
|
-
}
|
33393
|
-
}
|
33394
|
-
});
|
33395
|
-
|
33396
33536
|
if (settings.menu) {
|
33397
33537
|
self.aria('haspopup', true);
|
33398
33538
|
}
|
@@ -33442,11 +33582,13 @@ define("tinymce/ui/MenuItem", [
|
|
33442
33582
|
menu.itemDefaults = parent.settings.itemDefaults;
|
33443
33583
|
}
|
33444
33584
|
|
33445
|
-
menu = self.menu = Factory.create(menu).parent(self).renderTo(
|
33585
|
+
menu = self.menu = Factory.create(menu).parent(self).renderTo();
|
33446
33586
|
menu.reflow();
|
33447
33587
|
menu.fire('show');
|
33448
|
-
menu.on('cancel', function() {
|
33588
|
+
menu.on('cancel', function(e) {
|
33589
|
+
e.stopPropagation();
|
33449
33590
|
self.focus();
|
33591
|
+
menu.hide();
|
33450
33592
|
});
|
33451
33593
|
|
33452
33594
|
menu.on('hide', function(e) {
|
@@ -33454,6 +33596,8 @@ define("tinymce/ui/MenuItem", [
|
|
33454
33596
|
self.removeClass('selected');
|
33455
33597
|
}
|
33456
33598
|
});
|
33599
|
+
|
33600
|
+
menu.submenu = true;
|
33457
33601
|
} else {
|
33458
33602
|
menu.show();
|
33459
33603
|
}
|
@@ -33535,8 +33679,7 @@ define("tinymce/ui/MenuItem", [
|
|
33535
33679
|
'<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
|
33536
33680
|
(text !== '-' ? '<i class="' + icon + '"' + image + '></i> ' : '') +
|
33537
33681
|
(text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
|
33538
|
-
(shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
|
33539
|
-
shortcut + '</div>' : '') +
|
33682
|
+
(shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' + shortcut + '</div>' : '') +
|
33540
33683
|
(settings.menu ? '<div class="' + prefix + 'caret"></div>' : '') +
|
33541
33684
|
'</div>'
|
33542
33685
|
);
|
@@ -33562,7 +33705,32 @@ define("tinymce/ui/MenuItem", [
|
|
33562
33705
|
}
|
33563
33706
|
}
|
33564
33707
|
|
33565
|
-
|
33708
|
+
self.on('mouseenter click', function(e) {
|
33709
|
+
if (e.control === self) {
|
33710
|
+
if (!settings.menu && e.type === 'click') {
|
33711
|
+
self.fire('select');
|
33712
|
+
self.parent().hideAll();
|
33713
|
+
} else {
|
33714
|
+
self.showMenu();
|
33715
|
+
|
33716
|
+
if (e.aria) {
|
33717
|
+
self.menu.focus(true);
|
33718
|
+
}
|
33719
|
+
}
|
33720
|
+
}
|
33721
|
+
});
|
33722
|
+
|
33723
|
+
self._super();
|
33724
|
+
|
33725
|
+
return self;
|
33726
|
+
},
|
33727
|
+
|
33728
|
+
active: function(state) {
|
33729
|
+
if (typeof(state) != "undefined") {
|
33730
|
+
this.aria('checked', state);
|
33731
|
+
}
|
33732
|
+
|
33733
|
+
return this._super(state);
|
33566
33734
|
},
|
33567
33735
|
|
33568
33736
|
/**
|
@@ -33601,10 +33769,9 @@ define("tinymce/ui/MenuItem", [
|
|
33601
33769
|
*/
|
33602
33770
|
define("tinymce/ui/Menu", [
|
33603
33771
|
"tinymce/ui/FloatPanel",
|
33604
|
-
"tinymce/ui/KeyboardNavigation",
|
33605
33772
|
"tinymce/ui/MenuItem",
|
33606
33773
|
"tinymce/util/Tools"
|
33607
|
-
], function(FloatPanel,
|
33774
|
+
], function(FloatPanel, MenuItem, Tools) {
|
33608
33775
|
"use strict";
|
33609
33776
|
|
33610
33777
|
var Menu = FloatPanel.extend({
|
@@ -33612,7 +33779,9 @@ define("tinymce/ui/Menu", [
|
|
33612
33779
|
defaultType: 'menuitem',
|
33613
33780
|
border: 1,
|
33614
33781
|
layout: 'stack',
|
33615
|
-
role: '
|
33782
|
+
role: 'application',
|
33783
|
+
bodyRole: 'menu',
|
33784
|
+
ariaRoot: true
|
33616
33785
|
},
|
33617
33786
|
|
33618
33787
|
/**
|
@@ -33637,23 +33806,6 @@ define("tinymce/ui/Menu", [
|
|
33637
33806
|
|
33638
33807
|
self._super(settings);
|
33639
33808
|
self.addClass('menu');
|
33640
|
-
|
33641
|
-
self.keyNav = new KeyboardNavigation({
|
33642
|
-
root: self,
|
33643
|
-
enableUpDown: true,
|
33644
|
-
enableLeftRight: true,
|
33645
|
-
|
33646
|
-
leftAction: function() {
|
33647
|
-
if (self.parent() instanceof MenuItem) {
|
33648
|
-
self.keyNav.cancel();
|
33649
|
-
}
|
33650
|
-
},
|
33651
|
-
|
33652
|
-
onCancel: function() {
|
33653
|
-
self.fire('cancel', {}, false);
|
33654
|
-
self.hide();
|
33655
|
-
}
|
33656
|
-
});
|
33657
33809
|
},
|
33658
33810
|
|
33659
33811
|
/**
|
@@ -33681,7 +33833,6 @@ define("tinymce/ui/Menu", [
|
|
33681
33833
|
var self = this;
|
33682
33834
|
|
33683
33835
|
self.hideAll();
|
33684
|
-
self.fire('cancel');
|
33685
33836
|
self.fire('select');
|
33686
33837
|
},
|
33687
33838
|
|
@@ -33697,7 +33848,25 @@ define("tinymce/ui/Menu", [
|
|
33697
33848
|
|
33698
33849
|
return self._super();
|
33699
33850
|
},
|
33851
|
+
/*
|
33852
|
+
getContainerElm: function() {
|
33853
|
+
var doc = document, id = this.classPrefix + 'menucontainer';
|
33700
33854
|
|
33855
|
+
var elm = doc.getElementById(id);
|
33856
|
+
if (!elm) {
|
33857
|
+
elm = doc.createElement('div');
|
33858
|
+
elm.id = id;
|
33859
|
+
elm.setAttribute('role', 'application');
|
33860
|
+
elm.className = this.classPrefix + '-reset';
|
33861
|
+
elm.style.position = 'absolute';
|
33862
|
+
elm.style.top = elm.style.left = '0';
|
33863
|
+
elm.style.overflow = 'visible';
|
33864
|
+
doc.body.appendChild(elm);
|
33865
|
+
}
|
33866
|
+
|
33867
|
+
return elm;
|
33868
|
+
},
|
33869
|
+
*/
|
33701
33870
|
/**
|
33702
33871
|
* Invoked before the menu is rendered.
|
33703
33872
|
*
|
@@ -33911,7 +34080,7 @@ define("tinymce/ui/SplitButton", [
|
|
33911
34080
|
return MenuButton.extend({
|
33912
34081
|
Defaults: {
|
33913
34082
|
classes: "widget btn splitbtn",
|
33914
|
-
role: "
|
34083
|
+
role: "button"
|
33915
34084
|
},
|
33916
34085
|
|
33917
34086
|
/**
|
@@ -33961,7 +34130,7 @@ define("tinymce/ui/SplitButton", [
|
|
33961
34130
|
var icon = self.settings.icon ? prefix + 'ico ' + prefix + 'i-' + self.settings.icon : '';
|
33962
34131
|
|
33963
34132
|
return (
|
33964
|
-
'<div id="' + id + '" class="' + self.classes() + '">' +
|
34133
|
+
'<div id="' + id + '" class="' + self.classes() + '" role="button" tabindex="-1">' +
|
33965
34134
|
'<button type="button" hidefocus tabindex="-1">' +
|
33966
34135
|
(icon ? '<i class="' + icon + '"></i>' : '') +
|
33967
34136
|
(self._text ? (icon ? ' ' : '') + self._text : '') +
|
@@ -33989,7 +34158,7 @@ define("tinymce/ui/SplitButton", [
|
|
33989
34158
|
if (e.control == this) {
|
33990
34159
|
// Find clicks that is on the main button
|
33991
34160
|
while (node) {
|
33992
|
-
if (node.nodeName == 'BUTTON' && node.className.indexOf('open') == -1) {
|
34161
|
+
if ((e.aria && e.aria.key != 'down') || (node.nodeName == 'BUTTON' && node.className.indexOf('open') == -1)) {
|
33993
34162
|
e.stopImmediatePropagation();
|
33994
34163
|
onClickHandler.call(this, e);
|
33995
34164
|
return;
|
@@ -34084,13 +34253,19 @@ define("tinymce/ui/TabPanel", [
|
|
34084
34253
|
* @param {Number} idx Index of the tab to activate.
|
34085
34254
|
*/
|
34086
34255
|
activateTab: function(idx) {
|
34256
|
+
var activeTabElm;
|
34257
|
+
|
34087
34258
|
if (this.activeTabId) {
|
34088
|
-
|
34259
|
+
activeTabElm = this.getEl(this.activeTabId);
|
34260
|
+
DomUtils.removeClass(activeTabElm, this.classPrefix + 'active');
|
34261
|
+
activeTabElm.setAttribute('aria-selected', "false");
|
34089
34262
|
}
|
34090
34263
|
|
34091
34264
|
this.activeTabId = 't' + idx;
|
34092
34265
|
|
34093
|
-
|
34266
|
+
activeTabElm = this.getEl('t' + idx);
|
34267
|
+
activeTabElm.setAttribute('aria-selected', "true");
|
34268
|
+
DomUtils.addClass(activeTabElm, this.classPrefix + 'active');
|
34094
34269
|
|
34095
34270
|
if (idx != this.lastIdx) {
|
34096
34271
|
this.items()[this.lastIdx].hide();
|
@@ -34114,8 +34289,14 @@ define("tinymce/ui/TabPanel", [
|
|
34114
34289
|
layout.preRender(self);
|
34115
34290
|
|
34116
34291
|
self.items().each(function(ctrl, i) {
|
34292
|
+
var id = self._id + '-t' + i;
|
34293
|
+
|
34294
|
+
ctrl.aria('role', 'tabpanel');
|
34295
|
+
ctrl.aria('labelledby', id);
|
34296
|
+
|
34117
34297
|
tabsHtml += (
|
34118
|
-
'<div id="' +
|
34298
|
+
'<div id="' + id + '" class="' + prefix + 'tab" '+
|
34299
|
+
'unselectable="on" role="tab" aria-controls="' + ctrl._id + '" aria-selected="false" tabIndex="-1">' +
|
34119
34300
|
self.encode(ctrl.settings.title) +
|
34120
34301
|
'</div>'
|
34121
34302
|
);
|
@@ -34123,7 +34304,7 @@ define("tinymce/ui/TabPanel", [
|
|
34123
34304
|
|
34124
34305
|
return (
|
34125
34306
|
'<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
|
34126
|
-
'<div id="' + self._id + '-head" class="' + prefix + 'tabs">' +
|
34307
|
+
'<div id="' + self._id + '-head" class="' + prefix + 'tabs" role="tablist">' +
|
34127
34308
|
tabsHtml +
|
34128
34309
|
'</div>' +
|
34129
34310
|
'<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
|
@@ -34501,5 +34682,5 @@ define("tinymce/ui/Throbber", [
|
|
34501
34682
|
};
|
34502
34683
|
});
|
34503
34684
|
|
34504
|
-
expose(["tinymce/dom/EventUtils","tinymce/dom/Sizzle","tinymce/dom/DomQuery","tinymce/html/Styles","tinymce/dom/TreeWalker","tinymce/util/Tools","tinymce/dom/Range","tinymce/html/Entities","tinymce/Env","tinymce/dom/StyleSheetLoader","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/html/Node","tinymce/html/Schema","tinymce/html/SaxParser","tinymce/html/DomParser","tinymce/html/Writer","tinymce/html/Serializer","tinymce/dom/Serializer","tinymce/dom/TridentSelection","tinymce/util/VK","tinymce/dom/ControlSelection","tinymce/dom/
|
34685
|
+
expose(["tinymce/dom/EventUtils","tinymce/dom/Sizzle","tinymce/dom/DomQuery","tinymce/html/Styles","tinymce/dom/TreeWalker","tinymce/util/Tools","tinymce/dom/Range","tinymce/html/Entities","tinymce/Env","tinymce/dom/StyleSheetLoader","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/html/Node","tinymce/html/Schema","tinymce/html/SaxParser","tinymce/html/DomParser","tinymce/html/Writer","tinymce/html/Serializer","tinymce/dom/Serializer","tinymce/dom/TridentSelection","tinymce/util/VK","tinymce/dom/ControlSelection","tinymce/dom/RangeUtils","tinymce/dom/Selection","tinymce/Formatter","tinymce/UndoManager","tinymce/EnterKey","tinymce/ForceBlocks","tinymce/EditorCommands","tinymce/util/URI","tinymce/util/Class","tinymce/ui/Selector","tinymce/ui/Collection","tinymce/ui/DomUtils","tinymce/ui/Control","tinymce/ui/Factory","tinymce/ui/KeyboardNavigation","tinymce/ui/Container","tinymce/ui/DragHelper","tinymce/ui/Scrollable","tinymce/ui/Panel","tinymce/ui/Movable","tinymce/ui/Resizable","tinymce/ui/FloatPanel","tinymce/ui/Window","tinymce/ui/MessageBox","tinymce/WindowManager","tinymce/util/Quirks","tinymce/util/Observable","tinymce/Shortcuts","tinymce/Editor","tinymce/util/I18n","tinymce/FocusManager","tinymce/EditorManager","tinymce/LegacyInput","tinymce/util/XHR","tinymce/util/JSON","tinymce/util/JSONRequest","tinymce/util/JSONP","tinymce/util/LocalStorage","tinymce/Compat","tinymce/ui/Layout","tinymce/ui/AbsoluteLayout","tinymce/ui/Tooltip","tinymce/ui/Widget","tinymce/ui/Button","tinymce/ui/ButtonGroup","tinymce/ui/Checkbox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/ui/ComboBox","tinymce/ui/Path","tinymce/ui/ElementPath","tinymce/ui/FormItem","tinymce/ui/Form","tinymce/ui/FieldSet","tinymce/ui/FilePicker","tinymce/ui/FitLayout","tinymce/ui/FlexLayout","tinymce/ui/FlowLayout","tinymce/ui/FormatControls","tinymce/ui/GridLayout","tinymce/ui/Iframe","tinymce/ui/Label","tinymce/ui/Toolbar","tinymce/ui/MenuBar","tinymce/ui/MenuButton","tinymce/ui/ListBox","tinymce/ui/MenuItem","tinymce/ui/Menu","tinymce/ui/Radio","tinymce/ui/ResizeHandle","tinymce/ui/Spacer","tinymce/ui/SplitButton","tinymce/ui/StackLayout","tinymce/ui/TabPanel","tinymce/ui/TextBox","tinymce/ui/Throbber"]);
|
34505
34686
|
})(this);
|