-
Notifications
You must be signed in to change notification settings - Fork 5k
Description
Hi,
First of all thank you for a great product.
Overview
I'm working on an embed-able javascript widget: A one liner javascript to be included by third party websites that provides some service.
I've cloned the MDL repository and done partial review of the code structure.
I'm relatively new to front end web development, but understand that the current implementation intended for website development only and not suited for embedded widgets.
Motivation
I believe, it is not very complicated to make it suited for embedded widgets as well. It would be a great tool for widgets as it's light weight, doesn't have dependencies and just great.
I wanted to share my thoughts and tests I've done. Please tell me what you think, If I'm missing something and whether you think it would be good for the MDL project.
Why I believe TODAY MDL is not suited for embedded widgets
Some of the basic best practices to not interfere with the website and not let it interfere with the widget are:
1. Keep the global scope clear from javascript code (objects, functions, variables)
MDL sets all the components and componentHandler on the global window object
2. Do not interfere with CSS: encapsulate all the css in widgets container element
Although MDL has mdl-* prefix for all of it's classes, all the classes applied globally and there is no way to encapsulate it.
3. Load everything asynchronously to not interfere with the website loading times
It is not an issue but, would be great if MDL was encapsulated and exported as ECMAScript 6 module (I believe there are already opened issues on that topic).
Suggestions
Encapsulate the MDL Javascript
- Encapsulate components in single mdl object.
- Allow encapsulating mdl object in vendor scope.
- Or As alternative to option 2 - export as module.
I've done a small patch to see if encapsulating doesn't break MDL. Seems it doesn't as the JS Objects applied directly on the relevant DOM elements by the upgradeAllRegistered().
This is my patch (not suited for final solution):
Added wrapPatch.js to gulp SOURCES
const SOURCES = [
'src/wrapPatch.js',
// Component handler
'src/mdlComponentHandler.js',
/* ... */
} and excluded it from lint.
gulp.task('lint', () => {
return gulp.src([
'src/**/*.js',
'gulpfile.babel.js',
'!src/wrapPatch.js'
])
/* ... */
}Added args and params to iife
gulp.task('scripts', ['lint'], () => {
return gulp.src(SOURCES)
/* ... */
.pipe($.iife({useStrict: true, args: ['window','"MaVendor"'], params: ['gwindow','scope','window']}))
/* ... */
}And finally the wrapPatch.js:
if (false === (gwindow === window)) {
if ('undefined' === typeof window) {
window = {};
}
window.setTimeout = gwindow.setTimeout.bind(gwindow);
window.addEventListener = gwindow.addEventListener.bind(gwindow);
window.removeEventListener = gwindow.removeEventListener.bind(gwindow);
window.navigator = gwindow.navigator;
window.matchMedia = gwindow.matchMedia.bind(gwindow);
//window.requestAnimationFrame = gwindow.requestAnimationFrame;
//window.cancelAnimationFrame = gwindow.cancelAnimationFrame;
gwindow[scope] = gwindow[scope] || {};
gwindow[scope].mdl = window;
}I had to disable the mocha tests as well because they expect all the MDL components to be global.
NOTE: The mocha test are easily fixable, for example the first componentHandler Unit test it fixed by adding 2 lines at describe:
var componentHandler = window["MaVendor"].mdl.componentHandler;
var MaterialButton = window["MaVendor"].mdl.MaterialButton;For true solution instead of hard coded "MaVendor", the scope variable from the scripts gulp task should be injected.
This is the result:

As you can see all the MDL related objects are under: window.MaVendor.mdl.
MaterialComponentsNav and MaterialComponentsSnippets are related to the mdl website docs and not part of the release.
Encapsulate/Prefix the MDL CSS
I haven't review the CSS topic enough (wanted to post the issue first), but here are some thoughts:
Note: The thoughts below intended to give options for developers that build the library, not for the end users. It can be done by defining some variable that if the developer chooses to, will be able to add the prefix/encapsulating-class, instead of editing all the components manually.
For maximum flexibility of the end user maybe it is a good idea to expose it to the Custom CSS theme builder tool.
The resulting CSS should look something like this:
.encapsulating-class .mdl-button {
/* .... */
}Or
.encapsulating-class .prefix-mdl-button {
/* .... */
}The code is well organized and Sass is used for the CSS generation, so adding the encapsulation should not be an issue. All the imports are done by material-design-lite.scss
Add alternative resets suited for embedded widgets
Instead of the used resets maybe some combination with cleanslate can be used.


