GUAC-1378: Use <meta> tags instead of a special <guac-patch> root element.

This commit is contained in:
Michael Jumper
2016-02-18 17:13:47 -08:00
parent 9c11363224
commit f57a4f80db

View File

@@ -32,17 +32,193 @@ angular.module('index').config(['$provide', function($provide) {
var $q = $injector.get('$q');
/**
* Array of the root elements of all patches which should be applied to
* the HTML of retrieved templates.
* Array of the raw HTML of all patches which should be applied to the
* HTML of retrieved templates.
*
* @type Element[]
* @type String[]
*/
var patches = [
$('<guac-patch before="a"><p>HELLO BEFORE</p></guac-patch>')[0],
$('<guac-patch after="a"><p>HELLO AFTER</p></guac-patch>')[0],
$('<guac-patch replace="div.protocol"><div class="protocol">:-)</div></guac-patch>')[0]
'<meta name="before" content="a"><p>HELLO BEFORE</p>',
'<meta name="after" content="a"><p>HELLO AFTER</p>',
'<meta name="replace" content="div.protocol"><div class="protocol">:-)</div>'
];
/**
* Represents a single HTML patching operation which will be applied
* to the raw HTML of a template. The name of the patching operation
* MUST be one of the valid names defined within
* PatchOperation.Operations.
*
* @contructor
* @param {String} name
* The name of the patching operation that will be applied. Valid
* names are defined within PatchOperation.Operations.
*
* @param {String} selector
* The CSS selector which determines which elements within a
* template will be affected by the patch operation.
*/
var PatchOperation = function PatchOperation(name, selector) {
/**
* Applies this patch operation to the template defined by the
* given root element, which must be a single element wrapped by
* JQuery.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template to which
* this patch operation should be applied.
*
* @param {Element[]} elements
* The elements which should be applied by the patch
* operation. For example, if the patch operation is inserting
* elements, these are the elements that will be inserted.
*/
this.apply = function apply(root, elements) {
PatchOperation.Operations[name](root, selector, elements);
};
};
/**
* Mapping of all valid patch operation names to their corresponding
* implementations. Each implementation accepts the same three
* parameters: the root element of the template being patched, the CSS
* selector determining which elements within the template are patched,
* and an array of elements which make up the body of the patch.
*
* @type Object.<String, Function>
*/
PatchOperation.Operations = {
/**
* Inserts the given elements before the elements matched by the
* provided CSS selector.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template being
* patched.
*
* @param {String} selector
* The CSS selector which determines where this patch operation
* should be applied within the template defined by root.
*
* @param {Element[]} elements
* The contents of the patch which should be applied to the
* template defined by root at the locations selected by the
* given CSS selector.
*/
'before' : function before(root, selector, elements) {
root.find(selector).before(elements);
},
/**
* Inserts the given elements after the elements matched by the
* provided CSS selector.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template being
* patched.
*
* @param {String} selector
* The CSS selector which determines where this patch operation
* should be applied within the template defined by root.
*
* @param {Element[]} elements
* The contents of the patch which should be applied to the
* template defined by root at the locations selected by the
* given CSS selector.
*/
'after' : function after(root, selector, elements) {
root.find(selector).after(elements);
},
/**
* Replaces the elements matched by the provided CSS selector with
* the given elements.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template being
* patched.
*
* @param {String} selector
* The CSS selector which determines where this patch operation
* should be applied within the template defined by root.
*
* @param {Element[]} elements
* The contents of the patch which should be applied to the
* template defined by root at the locations selected by the
* given CSS selector.
*/
'replace' : function replace(root, selector, elements) {
root.find(selector).replaceWith(elements);
},
/**
* Inserts the given elements within the elements matched by the
* provided CSS selector, before any existing children.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template being
* patched.
*
* @param {String} selector
* The CSS selector which determines where this patch operation
* should be applied within the template defined by root.
*
* @param {Element[]} elements
* The contents of the patch which should be applied to the
* template defined by root at the locations selected by the
* given CSS selector.
*/
'before-children' : function beforeChildren(root, selector, elements) {
root.find(selector).prepend(elements);
},
/**
* Inserts the given elements within the elements matched by the
* provided CSS selector, after any existing children.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template being
* patched.
*
* @param {String} selector
* The CSS selector which determines where this patch operation
* should be applied within the template defined by root.
*
* @param {Element[]} elements
* The contents of the patch which should be applied to the
* template defined by root at the locations selected by the
* given CSS selector.
*/
'after-children' : function afterChildren(root, selector, elements) {
root.find(selector).append(elements);
},
/**
* Inserts the given elements within the elements matched by the
* provided CSS selector, replacing any existing children.
*
* @param {Element[]} root
* The JQuery-wrapped root element of the template being
* patched.
*
* @param {String} selector
* The CSS selector which determines where this patch operation
* should be applied within the template defined by root.
*
* @param {Element[]} elements
* The contents of the patch which should be applied to the
* template defined by root at the locations selected by the
* given CSS selector.
*/
'replace-children' : function replaceChildren(root, selector, elements) {
root.find(selector).empty().append(elements);
}
};
/**
* Invokes $templateRequest() with all arguments exactly as provided,
* applying all HTML patches from any installed Guacamole extensions
@@ -65,29 +241,38 @@ angular.module('index').config(['$provide', function($provide) {
// Apply all defined patches
angular.forEach(patches, function applyPatch(patch) {
// Ignore any patches which are malformed
if (patch.tagName !== 'GUAC-PATCH')
return;
var elements = $(patch);
// Insert after any elements which match the "after"
// selector (if defined)
var after = patch.getAttribute('after');
if (after)
root.find(after).after(patch.innerHTML);
// Filter out and parse all applicable meta tags
var operations = [];
elements = elements.filter(function filterMetaTags(index, element) {
// Insert before any elements which match the "before"
// selector (if defined)
var before = patch.getAttribute('before');
if (before)
root.find(before).before(patch.innerHTML);
// Leave non-meta tags untouched
if (element.tagName !== 'META')
return true;
// Replace any elements which match the "replace" selector
// (if defined)
var replace = patch.getAttribute('replace');
if (replace)
root.find(replace).html(patch.innerHTML);
// Only meta tags having a valid "name" attribute need
// to be filtered
var name = element.getAttribute('name');
if (!name || !(name in PatchOperation.Operations))
return true;
// Ignore all other attributes
// The "content" attribute must be present for any
// valid "name" meta tag
var content = element.getAttribute('content');
if (!content)
return true;
// Filter out and parse meta tag
operations.push(new PatchOperation(name, content));
return false;
});
// Apply each operation implied by the meta tags
angular.forEach(operations, function applyOperation(operation) {
operation.apply(root, elements);
});
});