tinymce-rails 4.0.16 → 4.0.18
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|