-
Notifications
You must be signed in to change notification settings - Fork 5
Loading of Resources
Last updated February 1, 2018 by akless - content is up-to-date for ccm v15.0.2
The ccm Framework provides a service for asynchronous loading of resources.
It could be used with the method ccm.load
.
With ccm.load
you can load resources like HTML, CSS, Images, JSON data and JavaScript on-demand and cross-domain.
On a single ccm.load
call several resources can be loaded at once.
It can be flexibly controlled which resources are loaded in serial and which in parallel.
The results are passed to the callback
.
ccm.load( resource1, resource2, ..., resourceX, callback )
Parameter | Description |
---|---|
resource1, resource2, ..., resourceX |
The resources to be loaded. |
callback |
Callback when all resources are loaded. |
Return Value
- Result(s) of the
ccm.load
call
(only if there were no asynchronous operations)
JavaScript Version:
- ECMAScript 6
In the following, all aspects of how to use ccm.load
are described in detail.
In the simplest case, only an URL is passed as a parameter for a resource to be loaded:
ccm.load( 'style.css' );
The URL of the resource can be a relative or an absolute path. The resource does not have to be within the same domain and can be loaded cross-domain.
Instead of an URL, an object can be passed, which then contains other information besides the URL, via which the loading of the resource is even more flexible controllable. For example, when loading a resource, it can be specified in which context it is loaded. The CSS contained in a CSS file can now also be loaded into a specific Shadow DOM:
const shadow = document.createElement( 'div' );
shadow.attachShadow( { mode: 'open' } );
ccm.load( { url: 'style.css', context: shadow } );
See here, here and here for more examples of loading CSS.
Here is a list of settings that can be made for loading a resource via such an object:
Property | Description |
---|---|
url | Required. URL of the resource. |
context | Context in which the resource should be loaded (default is <head> ). |
method | HTTP method to use: 'GET' , 'POST' or 'JSONP' (default is GET ). |
params | HTTP parameters to send (in the case of a data exchange). |
attr | HTML attributes to be set for the HTML tag that loads the resource. |
ignore_cache | Ignore any result already cached by ccm. |
type | Resource is loaded as css , image , data or js (default is data ). |
ccm.load
returns only a return value if no asynchronous operations have occurred.
This is only the case if all resources to be loaded were already loaded before and all results come directly from the ccm cache.
In any case, the results are passed to the callback
as the first parameter.
The following example loads the content "Hello, <b>World</b>!"
of a HTML file:
const first = ccm.load( 'hello.html', result => {
const second = ccm.load( 'hello.html', result => {} );
} );
first
is undefined
because the HTML content has to be loaded asynchronously.
second
is "Hello, <b>World</b>!"
because the content is already cached.
In any case result
contains the expected value.
If loading of at least one resource fails, ccm.load
will not return a result and the callback will not be called.
On a single ccm.load
call several resources can be loaded at once:
ccm.load( 'hello.html', 'style.css', 'image.png', console.log );
When multiple resources are loaded, the callback
receives an array instead of a single value as the result.
The array contains the results in the order in which the ccm.load
parameters were passed.
In this case, the result in the browser console is:
[ "Hello, <b>World</b>!", "style.css", "image.png" ]
.
If loading a resource does not supply anything specific, the default result is the URL of the resource. This applies, for example, when loading CSS and images.
It can be flexibly controlled which resources are loaded serially and which ones in parallel. By default, resources are loaded in parallel. When resources are to be loaded one after another, they simply need to be passed as an array:
ccm.load( [ 'hello.html', 'style.css' ] );
In the example, the two resources are now loaded serially.
The serial and parallel loading can be flexibly controlled as deep as desired. With each deeper array level you switch between serial and parallel loading:
ccm.load(
'hello.html', // Array Level 0: Parallel
[
'style.css', // Array Level 1: Serial
'image.png',
[
'data.json', // Array Level 2: Parallel
'script.js'
],
'logo.gif'
],
'picture.jpg'
);
The example loads the resources in the following timeline:
Resource | Timeline |
---|---|
hello.html |
******------------------ |
style.css |
******------------------ |
image.png |
------******------------ |
data.json |
------------******------ |
script.js |
------------******------ |
logo.gif |
------------------****** |
picture.jpg |
******------------------ |
Loading a JavaScript file will execute the JavaScript code contained in the file.
As a result of this resource ccm.load
returns the URL as usual.
But the loaded JavaScript code can also set the result individually:
/* script.js */
ccm.files[ 'script.js' ] = { foo: 'bar' };
ccm.load( 'script.js', console.log );
Loading this JavaScript file with ccm.load
results in: { foo: 'bar' }
.
ccm.load
returns as a result of loading a JavaScript file what the contained JavaScript code puts in ccm.files[ 'filename' ]
, where filename is the filename of the JavaScript file.
Otherwise, the result is the URL.
Using this convention, a JavaScript file can provide data across domains. Publicly fetched data in the namespace ccm.files
will be immediately deleted by ccm.
In case of a minimized JavaScript file, ".min" in filename can be omitted:
/* script.min.js */
ccm.files['script.js']={foo:'bar'};
ccm.load( 'script.min.js', console.log );
See here, here and here for more examples of loading JavaScript.
Data can be loaded via ccm.load
:
ccm.load( 'hello.php', console.log );
/* hello.php */
<?php
echo 'Hello, World!';
?>
The example returns as result in the browser console: "Hello, World!"
A Resource Data Object can be used to specify HTTP parameters to be transmitted:
ccm.load( {
url: 'echo.php',
params: { // sets HTTP parameters
name: 'John'
}
} , console.log );
/* echo.php */
<?php
echo 'Hello, '.filter_input( INPUT_GET, 'name', FILTER_SANITIZE_STRING );
?>
Result in the browser console: "Hello, John!"
The Resource Data Object can also be used to specify whether GET
or POST
should be used as HTTP method:
ccm.load( {
url: 'hello.php',
method: 'POST' // sets HTTP method
} , console.log );
By default, GET
is used.
JSONP can be used for data exchange.
In this case, it is always a GET
request.
JSONP is only necessary if the data is to be loaded cross-domain:
ccm.load( {
url: 'https://other.domain.com/data.php',
method: 'JSONP' // turns on JSONP
} , console.log );
/* data.php */
<?php
$callback = filter_input( INPUT_GET, 'callback', FILTER_SANITIZE_STRING );
echo $callback.'({"foo":"bar"});';
?>
Result in the browser console: { "foo": "bar" }
JSONP is not required if Cross-origin Resource Sharing (CORS) is already working.
See here for another example of a data exchange.
Normally ccm.load
automatically recognizes at the file extension how the resource should be loaded.
If a type
is specified in the Resource Data Object, the file extension of the resource is ignored and the resource is loaded as the specified type:
ccm.load( {
url: 'style.php',
type: 'css' // resource is loaded as CSS file
} );
/* style.php */
<?php
header( 'Content-Type: text/css' );
?>
b { color: red; }
Although the resource does not have the file extension .css
, it will be loaded like a CSS file.
The <head>
now contains: <link rel="stylesheet" type="text/css" href="style.php">
.
If type
is not specified and the file extension is unknown, a data exchange is assumed.
See here and here for another examples of loading a resource regardless of its file extension.
All Resource Data Objects passed to ccm.load
are cloned to prevent them from being changed externally.
When loading data or loading a CSS file in a specific context, the cache is always ignored.
In a Resource Data Object, the reference to a ccm Instance can also be passed for the property context
.
The resource is then loaded into the instance's Shadow DOM.
When a resource is loaded into a specific context, care must be taken that this context has DOM contact. The chosen context should not be an on-the-fly element or part of it. This is required so that the HTML element used to load the resource is evaluated by the browser.
ccm.load
always works with callbacks and never with "wait x ms and try again". There are therefore no unnecessary waiting times. If a resource is loaded that is already being loaded by another ccm.load
call, the resource will not be requested again. Instead, it waits and is informed immediately by callback when the resource is successfully loaded.
ccm.load( 'unit_tests/hello.html', console.log );
/* hello.html */
Hello, <b>World</b>!
Result in the browser console: "Hello, <b>World</b>!"
ccm.load( 'https://akless.github.io/ccm/unit_tests/dummy/data.json', console.log );
/* data.json */
{ "foo": "bar" }
Result in the browser console: { "foo": "bar" }
If you want to load the static data from a JSON file cross-domain, the data should instead be provided via a JavaScript file (see here and here). Then the static data is loaded with JSONP and the HTTP request is not blocked by the Same-origin Policy (SOP) of the browser. JSONP is not required if Cross-origin Resource Sharing (CORS) is already working.
ccm.load( 'https://akless.github.io/ccm/unit_tests/dummy/style.css', console.log );
The CSS rules contained in the CSS file are now active inside the global DOM.
The <head>
now contains:
<link rel="stylesheet" type="text/css" href="https://akless.github.io/ccm/unit_tests/dummy/style.css">
The result in the browser console is the URL of the CSS file:
https://akless.github.io/ccm/unit_tests/dummy/style.css
Loading of a CSS File in a Shadow DOM Context
const shadow = document.createElement( 'div' );
shadow.attachShadow( { mode: 'open' } );
ccm.load( {
url: 'https://akless.github.io/ccm/unit_tests/dummy/style.css',
context: shadow
} );
This time the CSS rules contained in the CSS file are now active inside the Shadow DOM and the <link>
element is appended to the shadow-root of shadow
.
Loading of a CSS File in the Shadow DOM of a ccm Instance
ccm.instance( 'https://akless.github.io/ccm-components/blank/ccm.blank.js', instance => {
ccm.load( {
url: 'https://akless.github.io/ccm/unit_tests/dummy/style.css',
context: instance
} );
} );
The CSS rules contained in the CSS file are now active inside the Shadow DOM of the ccm Instance and the <link>
element is appended to its shadow-root.
ccm.load( 'https://akless.github.io/ccm/unit_tests/dummy/image.png', callback );
From the moment the callback
is called, the loaded image is in the browser cache.
This example loads the JavaScript library jQuery v3.2.1.
ccm.load( 'https://code.jquery.com/jquery-3.2.1.js', console.log );
The code contained in the loaded JavaScript file is executed.
The <head>
now contains:
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
The result in the browser console is the URL of the JavaScript file:
https://code.jquery.com/jquery-3.2.1.js
Loading of a JavaScript File with Subresource Integrity
This is an example of setting HTML attributes for the HTML tag that loads a resource.
ccm.load( {
url: 'https://akless.github.io/ccm/unit_tests/dummy/script.js',
attr: {
integrity: 'sha384-QoLtnRwWkKw2xXw4o/pmW2Z1Zwst5f16sRMbRfP/Ova1nnEN6t2xUwiLOZ7pbbDW',
crossorigin: 'anonymous'
}
} );
The <head>
now contains:
<script src="https://akless.github.io/ccm/unit_tests/dummy/script.js"
integrity="sha384-QoLtnRwWkKw2xXw4o/pmW2Z1Zwst5f16sRMbRfP/Ova1nnEN6t2xUwiLOZ7pbbDW"
crossorigin="anonymous"></script>
ccm.load( 'https://akless.github.io/ccm/unit_tests/dummy/script.js', console.log );
/* script.js */
ccm.files[ 'script.js' ] = { foo: 'bar' };
Result in the browser console: { "foo": "bar" }
Loading of Data from a Server Interface with JSONP
This example performs a ccm demo login where you can authenticate yourself with any username and password.
ccm.load( {
url: 'https://ccm.inf.h-brs.de',
method: 'JSONP',
params: {
realm: 'ccm'
}
}, console.log );
The result in the browser console is { "id": "username", token: "password" }
, where username is the selected username and password is a server-side generated security token.
This example preloads an image that comes from a PHP interface.
ccm.load( {
url: 'https://kaul.inf.h-brs.de/ccm/dummy/image.php',
type: 'image'
} );
<?php
header( 'Content-Type: image/png' );
readfile( 'image.png' );
?>
If the PHP interface would additionally implement user authentication, images could be made available to specific user groups. An HTTP parameter could also be used to control which image should be delivered.
This example loads JavaScript that comes from a PHP interface.
ccm.load( {
url: 'https://kaul.inf.h-brs.de/ccm/dummy/js.php',
type: 'js'
}. console.log );
/* js.php */
ccm.files[ 'js.php' ] = { foo: '<? echo 'bar'; ?>' };
The <head>
now contains: <script src="https://kaul.inf.h-brs.de/ccm/dummy/js.php">
.
Result in the browser console: { "foo": "bar" }
Please contact me if anything is still incomprehensible or if you have any questions: [email protected]