Add AccessifyHTML5 and details polyfill as external files.
Technically being third-party libraries, these should be included in our combined plugins js file. Once that file is being generated, we can remove these to from serendipity_editor.js.tpl. References #189
This commit is contained in:
templates/2k11/admin/js
151
templates/2k11/admin/js/accessifyhtml5.js
Normal file
151
templates/2k11/admin/js/accessifyhtml5.js
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Accessifyhtml5.js
|
||||
*
|
||||
* Source: https://github.com/yatil/accessifyhtml5.js
|
||||
*/
|
||||
|
||||
var AccessifyHTML5 = function (defaults, more_fixes) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var fixes = {
|
||||
'article' : {'role': 'article' },
|
||||
'aside' : {'role': 'complementary' },
|
||||
'nav' : {'role': 'navigation' },
|
||||
'main' : {'role': 'main' },
|
||||
'output' : {'aria-live': 'polite' },
|
||||
'section' : {'role': 'region' },
|
||||
'[required]': {'aria-required': 'true' }
|
||||
},
|
||||
result = { ok:[], warn:[], fail:[] },
|
||||
error = result.fail,
|
||||
fix, elems, attr, value, key, obj, i, mo, by_match, el_label,
|
||||
ATTR_SECURE = new RegExp("aria-[a-z]+|role|tabindex|title|alt|data-[\\w-]+|lang|"
|
||||
+ "style|maxlength|placeholder|pattern|required|type|target|accesskey|longdesc"),
|
||||
ID_PREFIX = "acfy-id-",
|
||||
n_label = 0,
|
||||
Doc = document;
|
||||
|
||||
if (Doc.querySelectorAll) {
|
||||
|
||||
if (defaults) {
|
||||
if (defaults.header) {
|
||||
fixes[defaults.header] = {
|
||||
'role': 'banner'
|
||||
};
|
||||
}
|
||||
if (defaults.footer) {
|
||||
fixes[defaults.footer] = {
|
||||
'role': 'contentinfo'
|
||||
};
|
||||
}
|
||||
if (defaults.main) {
|
||||
fixes[defaults.main] = {
|
||||
'role': 'main'
|
||||
};
|
||||
fixes.main = {
|
||||
'role': ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Either replace fixes...
|
||||
if (more_fixes && more_fixes._CONFIG_
|
||||
&& more_fixes._CONFIG_.ignore_defaults) {
|
||||
fixes = more_fixes;
|
||||
} else {
|
||||
// ..Or concatenate - the default.
|
||||
for (mo in more_fixes) {
|
||||
fixes[mo] = more_fixes[mo];
|
||||
}
|
||||
}
|
||||
|
||||
for (fix in fixes) {
|
||||
|
||||
if (fix.match(/^_(CONFIG|[A-Z]+)_/)) {
|
||||
continue; // Silently ignore.
|
||||
}
|
||||
|
||||
if (fixes.hasOwnProperty(fix)) {
|
||||
|
||||
//Question: should we catch and report (or ignore) bad selector syntax?
|
||||
try {
|
||||
elems = Doc.querySelectorAll(fix);
|
||||
} catch (ex) {
|
||||
error.push({ sel:fix, attr:null, val:null,
|
||||
msg:"Invalid syntax for `document.querySelectorAll` function", ex:ex });
|
||||
}
|
||||
obj = fixes[fix];
|
||||
|
||||
if (!elems || elems.length < 1) {
|
||||
result.warn.push({ sel:fix, attr:null, val:null, msg:"Not found" });
|
||||
}
|
||||
|
||||
for (i = 0; i < elems.length; i++) {
|
||||
|
||||
for (key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
|
||||
attr = key;
|
||||
value = obj[key];
|
||||
|
||||
if (attr.match(/_?note/)) { // Ignore notes/comments.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!attr.match(ATTR_SECURE)) {
|
||||
error.push({ sel:fix, attr:attr, val:null, msg:"Attribute not allowed",
|
||||
re:ATTR_SECURE });
|
||||
continue;
|
||||
}
|
||||
if (!(typeof value).match(/string|number|boolean/)) {
|
||||
error.push({ sel:fix, attr:attr, val:value, msg:"Value-type not allowed" });
|
||||
continue;
|
||||
}
|
||||
|
||||
// Connect up 'aria-labelledby'. //Question: do we accept poor spelling/ variations?
|
||||
by_match = attr.match(/(describ|label)l?edby/);
|
||||
if (by_match) {
|
||||
try {
|
||||
el_label = Doc.querySelector(value); //Not: elems[i].querySel()
|
||||
} catch (ex) {
|
||||
error.push({ sel:fix, attr:attr, val:value,
|
||||
msg:"Invalid selector syntax (2) - see 'val'", ex:ex });
|
||||
}
|
||||
|
||||
if (! el_label) {
|
||||
error.push({ sel:fix, attr:attr, val:value,
|
||||
msg:"Labelledby ref not found - see 'val'" });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! el_label.id) {
|
||||
el_label.id = ID_PREFIX + n_label;
|
||||
}
|
||||
|
||||
value = el_label.id;
|
||||
attr = "aria-" + ("label" === by_match[1] ? "labelledby" : "describedby");
|
||||
|
||||
n_label++;
|
||||
}
|
||||
|
||||
if (!elems[i].hasAttribute(attr)) {
|
||||
elems[i].setAttribute(attr, value);
|
||||
|
||||
result.ok.push({ sel:fix, attr:attr, val:value, msg:"Added" });
|
||||
}
|
||||
else {
|
||||
result.warn.push({ sel:fix, attr:attr, val:value, msg:"Already present, skipped" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} //End: for (i..elems..i++)
|
||||
|
||||
}
|
||||
} //End: for (fix in fixes)
|
||||
}
|
||||
result.input = fixes;
|
||||
|
||||
return result;
|
||||
};
|
151
templates/2k11/admin/js/jquery.details.js
Normal file
151
templates/2k11/admin/js/jquery.details.js
Normal file
@ -0,0 +1,151 @@
|
||||
/*! http://mths.be/details v0.1.0 by @mathias | includes http://mths.be/noselect v1.0.3 */
|
||||
;(function(document, $) {
|
||||
|
||||
var proto = $.fn,
|
||||
details,
|
||||
// :'(
|
||||
isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]',
|
||||
// Feature test for native `<details>` support
|
||||
isDetailsSupported = (function(doc) {
|
||||
var el = doc.createElement('details'),
|
||||
fake,
|
||||
root,
|
||||
diff;
|
||||
if (!('open' in el)) {
|
||||
return false;
|
||||
}
|
||||
root = doc.body || (function() {
|
||||
var de = doc.documentElement;
|
||||
fake = true;
|
||||
return de.insertBefore(doc.createElement('body'), de.firstElementChild || de.firstChild);
|
||||
}());
|
||||
el.innerHTML = '<summary>a</summary>b';
|
||||
el.style.display = 'block';
|
||||
root.appendChild(el);
|
||||
diff = el.offsetHeight;
|
||||
el.open = true;
|
||||
diff = diff != el.offsetHeight;
|
||||
root.removeChild(el);
|
||||
if (fake) {
|
||||
root.parentNode.removeChild(root);
|
||||
}
|
||||
return diff;
|
||||
}(document)),
|
||||
toggleOpen = function($details, $detailsSummary, $detailsNotSummary, toggle) {
|
||||
var isOpen = $details.prop('open'),
|
||||
close = isOpen && toggle || !isOpen && !toggle;
|
||||
if (close) {
|
||||
$details.removeClass('open').prop('open', false).triggerHandler('close.details');
|
||||
$detailsSummary.attr('aria-expanded', false);
|
||||
$detailsNotSummary.hide();
|
||||
} else {
|
||||
$details.addClass('open').prop('open', true).triggerHandler('open.details');
|
||||
$detailsSummary.attr('aria-expanded', true);
|
||||
$detailsNotSummary.show();
|
||||
}
|
||||
};
|
||||
|
||||
/* http://mths.be/noselect v1.0.3 */
|
||||
proto.noSelect = function() {
|
||||
|
||||
// Since the string 'none' is used three times, storing it in a variable gives better results after minification
|
||||
var none = 'none';
|
||||
|
||||
// onselectstart and ondragstart for WebKit & IE
|
||||
// onmousedown for WebKit & Opera
|
||||
return this.bind('selectstart dragstart mousedown', function() {
|
||||
return false;
|
||||
}).css({
|
||||
'MozUserSelect': none,
|
||||
'msUserSelect': none,
|
||||
'webkitUserSelect': none,
|
||||
'userSelect': none
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Execute the fallback only if there’s no native `details` support
|
||||
if (isDetailsSupported) {
|
||||
|
||||
details = proto.details = function() {
|
||||
|
||||
return this.each(function() {
|
||||
var $details = $(this),
|
||||
$summary = $('summary', $details).first();
|
||||
$summary.attr({
|
||||
'role': 'button',
|
||||
'aria-expanded': $details.prop('open')
|
||||
}).on('click', function() {
|
||||
// the value of the `open` property is the old value
|
||||
var close = $details.prop('open');
|
||||
$summary.attr('aria-expanded', !close);
|
||||
$details.triggerHandler((close ? 'close' : 'open') + '.details');
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
details.support = isDetailsSupported;
|
||||
|
||||
} else {
|
||||
|
||||
details = proto.details = function() {
|
||||
|
||||
// Loop through all `details` elements
|
||||
return this.each(function() {
|
||||
|
||||
// Store a reference to the current `details` element in a variable
|
||||
var $details = $(this),
|
||||
// Store a reference to the `summary` element of the current `details` element (if any) in a variable
|
||||
$detailsSummary = $('summary', $details).first(),
|
||||
// Do the same for the info within the `details` element
|
||||
$detailsNotSummary = $details.children(':not(summary)'),
|
||||
// This will be used later to look for direct child text nodes
|
||||
$detailsNotSummaryContents = $details.contents(':not(summary)');
|
||||
|
||||
// If there is no `summary` in the current `details` element…
|
||||
if (!$detailsSummary.length) {
|
||||
// …create one with default text
|
||||
$detailsSummary = $('<summary>').text('Details').prependTo($details);
|
||||
}
|
||||
|
||||
// Look for direct child text nodes
|
||||
if ($detailsNotSummary.length != $detailsNotSummaryContents.length) {
|
||||
// Wrap child text nodes in a `span` element
|
||||
$detailsNotSummaryContents.filter(function() {
|
||||
// Only keep the node in the collection if it’s a text node containing more than only whitespace
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#space-character
|
||||
return this.nodeType == 3 && /[^ \t\n\f\r]/.test(this.data);
|
||||
}).wrap('<span>');
|
||||
// There are now no direct child text nodes anymore — they’re wrapped in `span` elements
|
||||
$detailsNotSummary = $details.children(':not(summary)');
|
||||
}
|
||||
|
||||
// Hide content unless there’s an `open` attribute
|
||||
$details.prop('open', typeof $details.attr('open') == 'string');
|
||||
toggleOpen($details, $detailsSummary, $detailsNotSummary);
|
||||
|
||||
// Add `role=button` and set the `tabindex` of the `summary` element to `0` to make it keyboard accessible
|
||||
$detailsSummary.attr('role', 'button').noSelect().prop('tabIndex', 0).on('click', function() {
|
||||
// Focus on the `summary` element
|
||||
$detailsSummary.focus();
|
||||
// Toggle the `open` and `aria-expanded` attributes and the `open` property of the `details` element and display the additional info
|
||||
toggleOpen($details, $detailsSummary, $detailsNotSummary, true);
|
||||
}).keyup(function(event) {
|
||||
if (32 == event.keyCode || (13 == event.keyCode && !isOpera)) {
|
||||
// Space or Enter is pressed — trigger the `click` event on the `summary` element
|
||||
// Opera already seems to trigger the `click` event when Enter is pressed
|
||||
event.preventDefault();
|
||||
$detailsSummary.click();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
details.support = isDetailsSupported;
|
||||
|
||||
}
|
||||
|
||||
}(document, jQuery));
|
Reference in New Issue
Block a user