Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit bf77109

Browse files
feat(layout): add md-css-only option, restore max-width for layouts
* support use of `<body class="md-css-only">` to use Layout features **without** any JS requirements or `ngMaterial` module dependencies. * May use standard Attribute selectors * May use class selectors * Disables Layout directive postlinks for optimization * restore `layout > flex` specifiers of max-width or max-height. * publish `$$mdLayout` service to allow Attribute selectors to be removed when the translation inject to Class selector finishes.
1 parent 9891723 commit bf77109

File tree

3 files changed

+262
-74
lines changed

3 files changed

+262
-74
lines changed

src/core/services/layout/layout.js

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
(function () {
22
'use strict';
33

4+
var _$$mdLayout, _$parse;
5+
46
/**
57
*
68
* The original ngMaterial Layout solution used attribute selectors and CSS.
@@ -42,6 +44,26 @@
4244
*/
4345
angular.module('material.core.layout', [ 'ng' ])
4446

47+
/**
48+
* Model of flags used by the Layout directives
49+
* Allows changes while running tests or runtime app changes
50+
*/
51+
.factory("$$mdLayout", function() {
52+
return {
53+
/**
54+
* Should we remove the original layout Attribute selectors
55+
* after translation injection
56+
*/
57+
removeAttributes : true,
58+
59+
/**
60+
* Special internal flag used to optimize
61+
* noop(s) for the directive postLinks below
62+
*/
63+
disablePostLinks : undefined
64+
};
65+
})
66+
4567
// Attribute directives with optional value(s)
4668

4769
.directive('layout' , attributeWithObserve('layout' , true) )
@@ -136,32 +158,44 @@
136158
* @param {boolean=} addDirectiveAsClass
137159
*/
138160
function attributeWithObserve(className, addDirectiveAsClass) {
139-
return function() {
161+
return ['$$mdLayout', '$document', '$parse', function($$mdLayout, $document, $parse) {
162+
_$$mdLayout = $$mdLayout;
163+
_$parse = $parse;
164+
140165
return {
141166
restrict : 'A',
142167
compile: function(element, attr) {
168+
if ( postLinkIsDisabled($document[0]) ) return angular.noop;
169+
143170
attributeValueToClass(null, element, attr);
144171

145172
// Use for postLink to account for transforms after ng-transclude.
146173
return attributeValueToClass;
147174
}
148175
};
149-
};
176+
}];
177+
178+
150179

151180
/**
152181
* Add as transformed class selector(s), then
153182
* remove the deprecated attribute selector
154183
*/
155184
function attributeValueToClass(scope, element, attr) {
156185
var directive = attr.$normalize(className);
186+
var attrExpression = _$parse( directive[directive] );
157187

158188
// Add transformed class selector(s)
159189
if (addDirectiveAsClass) {
160190
element.addClass(className);
161191
}
162192

163-
if (attr[directive]) {
193+
if ( attr[directive] ) {
164194
element.addClass(className + "-" + attr[directive].replace(/\s+/g, "-"));
195+
196+
if ( _$$mdLayout.removeAttributes ) {
197+
element.removeAttr(directive);
198+
}
165199
}
166200

167201
if ( scope ) {
@@ -170,15 +204,15 @@
170204
* Instead watch the attribute so interpolated data-bindings to layout
171205
* selectors will continue to be supported.
172206
*
173-
* $observe the className and update with new class (after removing the last one)
207+
* $observe() the className and update with new class (after removing the last one)
174208
*
175209
* e.g. `layout="{{layoutDemo.direction}}"` will update...
176210
*/
177211
var lastClass;
178212

179213
attr.$observe(function() {
180214

181-
return attr[className];
215+
return attrExpression(scope);
182216

183217
}, function(newVal) {
184218

@@ -200,17 +234,20 @@
200234
* This is a `simple` transpose of attribute usage to class usage
201235
*/
202236
function attributeWithoutValue(className) {
203-
return function() {
237+
return ['$$mdLayout', '$document', function($$mdLayout, $document) {
238+
_$$mdLayout = $$mdLayout;
204239
return {
205240
restrict : 'A',
206241
compile: function(element, attr) {
242+
if ( postLinkIsDisabled($document[0]) ) return angular.noop;
243+
207244
attributeToClass(null, element);
208245

209246
// Use for postLink to account for transforms after ng-transclude.
210247
return attributeToClass;
211248
}
212249
};
213-
};
250+
}];
214251

215252
/**
216253
* Add as transformed class selector, then
@@ -219,7 +256,7 @@
219256
function attributeToClass(scope, element) {
220257
element.addClass(className);
221258

222-
if ( scope ) {
259+
if ( scope && _$$mdLayout.removeAttributes ) {
223260
// After link-phase, remove deprecated layout attribute selector
224261
element.removeAttr(className);
225262
}
@@ -239,4 +276,32 @@
239276

240277
}
241278

279+
/**
280+
* Scan the body element. If it has a class 'md-css-only', then do NOT
281+
* postLink process the directives for Attribute selectors.
282+
* (recall that postlink injects Class selectors based on attribute selector settings)
283+
*
284+
* Instead the Layout CSS for Attributes is used:
285+
* e.g
286+
* .md-css-only [layout=row] {
287+
* flex-direction: row;
288+
* -webkit-flex-direction: row;
289+
* }
290+
*
291+
* Note: this means that 'md-css-only' will not work for IE (due to performance issues)
292+
* In these cases, the Layout translators (directives) should be enabled.
293+
*/
294+
function postLinkIsDisabled(document) {
295+
var disablePostLinks = _$$mdLayout.disablePostLinks;
296+
297+
if ( angular.isUndefined(disablePostLinks) ) {
298+
var body = document.querySelectorAll("body")[0];
299+
var styles = body.getAttribute('class');
300+
301+
disablePostLinks = styles ? (styles.indexOf('md-css-only') > -1) : false;
302+
}
303+
304+
return _$$mdLayout.disablePostLinks = disablePostLinks;
305+
}
306+
242307
})();

0 commit comments

Comments
 (0)