champion-8.x-3.1-no-core/modules/contrib/hax/hax.module
modules/contrib/hax/hax.module
<?php /** * @file * Headless Authoring eXperience, accept calls and make things haxable. */ use Drupal\hax\HaxService; /** * Implements hook_preprocess_hook(). * * Add cms-hax tag and related markup as wrapper to body field. */ function hax_preprocess_field(&$vars) { // Supporting attachments handled in hax_page_attachments(). // Allow for cache variability based on route name so this can be handled // evaluated separately for the view and the hax mode tabs. $vars['#cache']['contexts'][] = 'route.name'; if (!hax_is_current_route_supported()) { return; } $entity_type = $vars['element']['#object']->getEntityTypeId(); $view_mode = $vars['element']['#view_mode']; // @todo we could do this to other things too but this is the piece that forces it to body only if ($vars['field_name'] == 'body' && $entity_type == 'node' && $view_mode == 'full' && \Drupal::config('hax.settings')->get('hax_autoload_element_node_view')) { $appStoreConnection = json_encode([ 'url' => base_path() . 'hax-app-store/' . \Drupal::csrfToken()->get(), ]); // Get the NID from current path. $request = \Drupal::request(); $current_path = $request->getPathInfo(); $path_args = explode('/', $current_path); $node_id = $path_args[2]; // @todo this is clunky but works $redirect = str_replace('//', '/', base_path() . str_replace('/hax', '', $current_path)); // TODO Not ideal, but we've fallen back to using the body text instead of // prefix/suffix due to filtering. This will go through the node's selected // text format for render. // @todo: convert to string replacement function or template. $vars['items'][0]['content']['#text'] = '<cms-hax redirect-location="' . $redirect . '" open-default end-point="' . base_path() . 'hax-node-save/' . $node_id . '/' . \Drupal::csrfToken() ->get() . '" app-store-connection=' . "'" . $appStoreConnection . "'" . '><template>' . $vars['items'][0]['content']['#text'] . '</template></cms-hax>'; } } /** * Implements hook_hax_app_store(). */ function hax_hax_app_store() { $config = \Drupal::config('hax.settings'); $hax = new HaxService(); $apikeys = []; $baseApps = $hax->baseSupportedApps(); foreach ($baseApps as $key => $app) { if ($config->get('hax_' . $key . '_key') != '') { $apikeys[$key] = $config->get('hax_' . $key . '_key'); } } $json = $hax->loadBaseAppStore($apikeys); // Pull in the core ones we supply. if (\Drupal::moduleHandler()->moduleExists('file')) { $tmp = json_decode(_hax_site_connection()); array_push($json, $tmp); } return $json; } /** * Implements hook_hax_blox(). */ function hax_hax_blox() { $hax = new HAXService(); $blox = $hax->loadBaseBlox(); return $blox; } /** * Implements hook_hax_stax(). */ function hax_hax_stax() { $hax = new HAXService(); $stax = $hax->loadBaseStax(); return $stax; } /** * Implements hook_hax_autoloader(). */ function hax_hax_autoloader() { // Generate autoload list. $autoloaderstring = \Drupal::config('hax.settings') ->get('hax_autoload_element_list'); // Blow up based on space. $autoloader = explode(' ', $autoloaderstring); return $autoloader; } /** * Hax site connection. * * Connection details for this site. This is where all the really important * stuff is that will make people freak out. */ function _hax_site_connection() { global $base_url; $parts = explode('://', $base_url); // Built in support when file_entity and restws is in place. $title = t('Internal files'); $json = '{ "details": { "title": "' . $title . '", "icon": "perm-media", "color": "light-blue", "author": "Drupal", "description": "Drupal site integration for HAX", "tags": ["media", "drupal"] }, "connection": { "protocol": "' . $parts[0] . '", "url": "' . $parts[1] . '", "operations": { "browse": { "method": "GET", "endPoint": "file.json", "pagination": { "style": "link", "props": { "first": "page.first", "next": "page.next", "previous": "page.previous", "last": "page.last" } }, "search": { }, "data": { }, "resultMap": { "defaultGizmoType": "image", "items": "list", "preview": { "title": "name", "details": "mime", "image": "url", "id": "uuid" }, "gizmo": { "source": "url", "id": "uuid", "title": "name", "type": "type" } } }, "add": { "method": "POST", "endPoint": "hax-file-save/' . \Drupal::csrfToken()->get() . '", "acceptsGizmoTypes": [ "image", "video", "audio", "pdf", "svg", "document", "csv" ], "resultMap": { "item": "data.file", "defaultGizmoType": "image", "gizmo": { "source": "url", "id": "uuid" } } } } } }'; return $json; } /** * Implements hook_page_bottom(). * * Load all attachments for this page. */ function hax_page_bottom(array &$page_bottom) { $location = \Drupal::config('hax.settings')->get('hax_project_location'); // account for custom locations if ($location == 'other') { $location = \Drupal::config('hax.settings')->get('hax_project_location_other'); } // append base_path if this site has a url to start it if (strpos($location, 'http') === FALSE) { $location = base_path() . $location; } $wc = new WebComponentsService(); $page_bottom['hax'] = [ '#type' => 'inline_template', '#template' => '{{ somecontent|raw }}', '#context' => [ 'somecontent' => $wc->applyWebcomponents($location) ] ]; } /** * Identify whether the current route is supported for HAX deployment. * * @return bool * TRUE if the current route is supported. */ function hax_is_current_route_supported() { $route_name = \Drupal::routeMatch()->getRouteName(); if ($route_name == 'hax.node_form') { return TRUE; } return FALSE; } /** * Class for implementing web component polyfills and other header aspects in a uniform manner */ class WebComponentsService { /** * This applies all pieces of a standard build appended to the header */ public function applyWebcomponents($directory = '/', $files = array('build.js')) { return $this->getBuild($directory, $files); } /** * Front end logic for ES5-AMD, ES6-AMD, ES6 version to deliver */ public function getBuild($directory = '/', $files = array('build.js')) { $es5 = array(); $es6Amd = array(); $es6 = array(); foreach ($files as $file) { array_push($es5, 'cdn + "build/es5-amd/' . $file . '"'); array_push($es6Amd, 'cdn + "build/es6-amd/' . $file . '"'); array_push($es6, 'import "' . $directory . 'build/es6/' . $file . '";'); } return '<script>var cdn="' . $directory . '";var old=false; try { new Function(\'import("")\'); } catch (err) { if (typeof Symbol == "undefined") { // IE 11, at least try to serve the components if (!(window.ActiveXObject) && "ActiveXObject" in window) { "use strict"; (function () { function a(a, b, c) { var d = a; if (d.state = b, d.stateData = c, 0 < d.onNextStateChange.length) { var e = d.onNextStateChange.slice(); d.onNextStateChange.length = 0; for (var f, g = 0, h = e; g < h.length; g++)f = h[g], f() } return d } function b(b) { function d() { try { document.head.removeChild(f) } catch (a) { } } var e = a(b, "Loading", void 0), f = document.createElement("script"); return f.src = b.url, f.onload = function () { var a, b, f; void 0 === r ? (b = [], f = void 0) : (a = r(), b = a[0], f = a[1]), c(e, b, f), d() }, f.onerror = function () { g(b, new TypeError("Failed to fetch " + b.url)), d() }, document.head.appendChild(f), e } function c(b, c, e) { var f = d(b, c), g = f[0], h = f[1]; return a(b, "WaitingForTurn", { args: g, deps: h, moduleBody: e }) } function d(a, c) { for (var e, f = [], g = [], i = 0, j = c; i < j.length; i++) { if (e = j[i], "exports" === e) { f.push(a.exports); continue } if ("require" === e) { f.push(function (b, c, e) { var f = d(a, b), g = f[0], i = f[1]; h(i, function () { c && c.apply(null, g) }, e) }); continue } if ("meta" === e) { f.push({ url: !0 === a.isTopLevel ? a.url.substring(0, a.url.lastIndexOf("#")) : a.url }); continue } var l = k(n(a.urlBase, e)); f.push(l.exports), g.push(l), "Initialized" === l.state && b(l) } return [f, g] } function e(b) { var c = a(b, "WaitingOnDeps", b.stateData); return h(b.stateData.deps, function () { return f(c) }, function (a) { return g(c, a) }), c } function f(b) { var c = b.stateData; if (null != c.moduleBody) try { c.moduleBody.apply(null, c.args) } catch (a) { return g(b, a) } return a(b, "Executed", void 0) } function g(b, c) { return !0 === b.isTopLevel && setTimeout(function () { throw c }), a(b, "Failed", c) } function h(a, b, c) { var d = a.shift(); return void 0 === d ? void (b && b()) : "WaitingOnDeps" === d.state ? (!1, void h(a, b, c)) : void i(d, function () { h(a, b, c) }, c) } function i(a, b, c) { switch (a.state) { case "WaitingForTurn": return e(a), void i(a, b, c); case "Failed": return void (c && c(a.stateData)); case "Executed": return void b(); case "Loading": case "WaitingOnDeps": return void a.onNextStateChange.push(function () { return i(a, b, c) }); case "Initialized": throw new Error("All dependencies should be loading already before pressureDependencyToExecute is called."); default: throw new Error("Impossible module state: " + a.state); } } function j(a, b) { switch (a.state) { case "Executed": case "Failed": return void b(); default: a.onNextStateChange.push(function () { return j(a, b) }); } } function k(a) { var b = q[a]; return void 0 === b && (b = q[a] = { url: a, urlBase: m(a), exports: Object.create(null), state: "Initialized", stateData: void 0, isTopLevel: !1, onNextStateChange: [] }), b } function l(a) { return v.href = a, v.href } function m(a) { return a = a.split("?")[0], a = a.split("#")[0], a.substring(0, a.lastIndexOf("/") + 1) } function n(a, b) { return -1 === b.indexOf("://") ? l("/" === b[0] ? b : a + b) : b } function o() { return document.baseURI || (document.querySelector("base") || window.location).href } function p() { var b = document.currentScript; if (!b) return u; if (window.HTMLImports) { var c = window.HTMLImports.importForElement(b); return c ? c.href : u } var d = b.ownerDocument.createElement("a"); return d.href = "", d.href } if (!window.define) { var q = Object.create(null), r = void 0, s = 0, t = void 0, u = o(); window.define = function (a, b) { var d = !1; r = function () { return d = !0, r = void 0, [a, b] }; var f = p(); setTimeout(function () { if (!1 == d) { r = void 0; var g = f + "#" + s++, h = k(g); h.isTopLevel = !0; var i = c(h, a, b); void 0 === t ? e(i) : j(k(t), function () { e(i) }), t = g } }, 0) }, window.define._reset = function () { for (var a in q) delete q[a]; r = void 0, s = 0, t = void 0, u = o() }; var v = document.createElement("a") } })(); var defs = [ cdn + "build/es5-amd/node_modules/web-animations-js/web-animations-next-lite.min.js", cdn + "build/es5-amd/node_modules/promise-polyfill/dist/polyfill.min.js", cdn + "build/es5-amd/node_modules/fetch-ie8/fetch.js", cdn + "babel/babel-top.js" ]; defs.push(' . implode(',', $es5) . '); define(defs, function () { "use strict" }); define([cdn + "build/es5-amd/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"], function () { "use strict" }); } } else { "use strict"; (function () { function a(a, b, c) { var d = a; if (d.state = b, d.stateData = c, 0 < d.onNextStateChange.length) { var e = d.onNextStateChange.slice(); d.onNextStateChange.length = 0; for (var f, g = 0, h = e; g < h.length; g++)f = h[g], f() } return d } function b(b) { function d() { try { document.head.removeChild(f) } catch (a) { } } var e = a(b, "Loading", void 0), f = document.createElement("script"); return f.src = b.url, f.onload = function () { var a, b, f; void 0 === r ? (b = [], f = void 0) : (a = r(), b = a[0], f = a[1]), c(e, b, f), d() }, f.onerror = function () { g(b, new TypeError("Failed to fetch " + b.url)), d() }, document.head.appendChild(f), e } function c(b, c, e) { var f = d(b, c), g = f[0], h = f[1]; return a(b, "WaitingForTurn", { args: g, deps: h, moduleBody: e }) } function d(a, c) { for (var e, f = [], g = [], i = 0, j = c; i < j.length; i++) { if (e = j[i], "exports" === e) { f.push(a.exports); continue } if ("require" === e) { f.push(function (b, c, e) { var f = d(a, b), g = f[0], i = f[1]; h(i, function () { c && c.apply(null, g) }, e) }); continue } if ("meta" === e) { f.push({ url: !0 === a.isTopLevel ? a.url.substring(0, a.url.lastIndexOf("#")) : a.url }); continue } var l = k(n(a.urlBase, e)); f.push(l.exports), g.push(l), "Initialized" === l.state && b(l) } return [f, g] } function e(b) { var c = a(b, "WaitingOnDeps", b.stateData); return h(b.stateData.deps, function () { return f(c) }, function (a) { return g(c, a) }), c } function f(b) { var c = b.stateData; if (null != c.moduleBody) try { c.moduleBody.apply(null, c.args) } catch (a) { return g(b, a) } return a(b, "Executed", void 0) } function g(b, c) { return !0 === b.isTopLevel && setTimeout(function () { throw c }), a(b, "Failed", c) } function h(a, b, c) { var d = a.shift(); return void 0 === d ? void (b && b()) : "WaitingOnDeps" === d.state ? (!1, void h(a, b, c)) : void i(d, function () { h(a, b, c) }, c) } function i(a, b, c) { switch (a.state) { case "WaitingForTurn": return e(a), void i(a, b, c); case "Failed": return void (c && c(a.stateData)); case "Executed": return void b(); case "Loading": case "WaitingOnDeps": return void a.onNextStateChange.push(function () { return i(a, b, c) }); case "Initialized": throw new Error("All dependencies should be loading already before pressureDependencyToExecute is called."); default: throw new Error("Impossible module state: " + a.state); } } function j(a, b) { switch (a.state) { case "Executed": case "Failed": return void b(); default: a.onNextStateChange.push(function () { return j(a, b) }); } } function k(a) { var b = q[a]; return void 0 === b && (b = q[a] = { url: a, urlBase: m(a), exports: Object.create(null), state: "Initialized", stateData: void 0, isTopLevel: !1, onNextStateChange: [] }), b } function l(a) { return v.href = a, v.href } function m(a) { return a = a.split("?")[0], a = a.split("#")[0], a.substring(0, a.lastIndexOf("/") + 1) } function n(a, b) { return -1 === b.indexOf("://") ? l("/" === b[0] ? b : a + b) : b } function o() { return document.baseURI || (document.querySelector("base") || window.location).href } function p() { var b = document.currentScript; if (!b) return u; if (window.HTMLImports) { var c = window.HTMLImports.importForElement(b); return c ? c.href : u } var d = b.ownerDocument.createElement("a"); return d.href = "", d.href } if (!window.define) { var q = Object.create(null), r = void 0, s = 0, t = void 0, u = o(); window.define = function (a, b) { var d = !1; r = function () { return d = !0, r = void 0, [a, b] }; var f = p(); setTimeout(function () { if (!1 == d) { r = void 0; var g = f + "#" + s++, h = k(g); h.isTopLevel = !0; var i = c(h, a, b); void 0 === t ? e(i) : j(k(t), function () { e(i) }), t = g } }, 0) }, window.define._reset = function () { for (var a in q) delete q[a]; r = void 0, s = 0, t = void 0, u = o() }; var v = document.createElement("a") } })(); var defs = [ cdn + "build/es6-amd/node_modules/web-animations-js/web-animations-next-lite.min.js", cdn + "babel/babel-top.js" ]; if (window.customElements) { // certain FF / Safari versions defs.push(cdn + "build/es6-amd/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"); } else { defs.push(cdn + "build/es6-amd/node_modules/promise-polyfill/dist/polyfill.min.js"); defs.push(cdn + "build/es6-amd/node_modules/fetch-ie8/fetch.js"); defs.push(cdn + "build/es6-amd/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"); } defs.push(' . implode(',', $es6Amd) . '); define(defs, function () { "use strict" }); } old=true; } </script> <script>if(old)document.write(\'<!--\');</script> <script async defer type="module"> ' . implode("\n", $es6) . ' </script> <script async src="' . $directory . 'build/es6/node_modules/web-animations-js/web-animations-next-lite.min.js"> //<!--! do not remove --> </script>'; } }