From 789128bdafd5570b3b298af1b7f29729e970ae17 Mon Sep 17 00:00:00 2001 From: Hydraner Date: Tue, 17 Mar 2020 18:05:01 +0100 Subject: [PATCH 001/330] Implement exclude tags feature. --- packages/core/src/lib/uikitExcludePattern.js | 6 ++- .../core/test/uikitExcludePattern_tests.js | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/core/src/lib/uikitExcludePattern.js b/packages/core/src/lib/uikitExcludePattern.js index 61cddcb57..5cb7cd5e1 100644 --- a/packages/core/src/lib/uikitExcludePattern.js +++ b/packages/core/src/lib/uikitExcludePattern.js @@ -1,7 +1,11 @@ 'use strict'; +var _ = require('lodash'); + const uikitExcludePattern = (pattern, uikit) => { const state = pattern.patternState; - return uikit.excludedPatternStates.includes(state); + const tags = pattern.tags; + + return uikit.excludedPatternStates.includes(state) || _.intersection(uikit.excludedTags, tags).length > 0; }; module.exports = uikitExcludePattern; diff --git a/packages/core/test/uikitExcludePattern_tests.js b/packages/core/test/uikitExcludePattern_tests.js index a31f4c3f3..24b4881c9 100644 --- a/packages/core/test/uikitExcludePattern_tests.js +++ b/packages/core/test/uikitExcludePattern_tests.js @@ -46,6 +46,53 @@ tap.test( //act const result = uikitExcludePattern(pattern, uikit); + //assert + test.true(result); + test.end(); + } + +tap.test( + 'uikitExcludePattern - returns false when uikit has no excluded tags', + test => { + //arrange + const uikit = { excludedTags: [] }; + const pattern = { tags: 'foo-tag' }; + + //act + const result = uikitExcludePattern(pattern, uikit); + + //assert + test.false(result); + test.end(); + } +); + +tap.test( + 'uikitExcludePattern - returns false pattern does not have same tags as uikit exclusions', + test => { + //arrange + const uikit = { excludedTags: ['bat-tag'] }; + const pattern = { tags: 'foo-tag' }; + + //act + const result = uikitExcludePattern(pattern, uikit); + + //assert + test.false(result); + test.end(); + } +); + +tap.test( + 'uikitExcludePattern - returns true when uikit has same tags as pattern', + test => { + //arrange + const uikit = { excludedTags: ['bar-tag', 'foo-tag'] }; + const pattern = { tags: 'foo-tag' }; + + //act + const result = uikitExcludePattern(pattern, uikit); + //assert test.true(result); test.end(); From 22373013b0bb56df76b6c4070fd3799e22b1324a Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Sun, 12 Apr 2020 02:20:00 +0200 Subject: [PATCH 002/330] Update object_factory and view all page behavior --- .prettierrc | 3 +- packages/core/src/lib/object_factory.js | 156 ++++++++++-------- packages/core/src/lib/ui_builder.js | 84 ++++------ packages/core/test/object_factory_tests.js | 40 ++--- .../src/scripts/components/pl-nav/pl-nav.js | 2 +- 5 files changed, 141 insertions(+), 144 deletions(-) diff --git a/.prettierrc b/.prettierrc index c1a6f6671..d81dbaeb5 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "singleQuote": true, - "trailingComma": "es5" + "trailingComma": "es5", + "endOfLine": "auto" } diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 83524a9c7..27cf771b1 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -1,18 +1,27 @@ 'use strict'; -const patternEngines = require('./pattern_engines'); + +const _ = require('lodash'); const path = require('path'); +const patternEngines = require('./pattern_engines'); -// patternPrefixMatcher is intended to match the leading maybe-underscore, +// prefixMatcher is intended to match the leading maybe-underscore, // zero or more digits, and maybe-dash at the beginning of a pattern file name we can hack them // off and get at the good part. -const patternPrefixMatcher = /^_?(\d+-)?/; +const prefixMatcher = /^_?(\d+-)?/; -// Pattern properties /** - * Pattern constructor + * Pattern constructor / Pattern properties + * + * Before changing functionalities of the pattern object please read the following pull requests + * to get more details about the behavior of the folder structure + * https://github.com/pattern-lab/patternlab-node/pull/992 + * https://github.com/pattern-lab/patternlab-node/pull/1016 + * * @constructor */ const Pattern = function(relPath, data, patternlab) { + this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' + /** * We expect relPath to be the path of the pattern template, relative to the * root of the pattern tree. Parse out the path parts and save the useful ones. @@ -20,89 +29,49 @@ const Pattern = function(relPath, data, patternlab) { * @param {data} The JSON used to render values in the pattern. * @param {patternlab} rendered html files for the pattern */ - const pathObj = path.parse(path.normalize(relPath)); - const info = {}; - // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors - info.hasDir = - path.basename(pathObj.dir).replace(patternPrefixMatcher, '') === - pathObj.name.replace(patternPrefixMatcher, '') || - path.basename(pathObj.dir).replace(patternPrefixMatcher, '') === - pathObj.name.split('~')[0].replace(patternPrefixMatcher, ''); - - info.dir = info.hasDir ? pathObj.dir.split(path.sep).pop() : ''; - info.dirLevel = pathObj.dir.split(path.sep).length; + const pathObj = path.parse(this.relPath); + + const info = this.getPatternInfo(pathObj); - this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' this.fileName = pathObj.name; // '00-colors' this.subdir = pathObj.dir; // '00-atoms/00-global' - if ((this.subdir.match(/\w(?=\\)|\w(?=\/)/g) || []).length > 1) { - this.subdir = this.subdir.split(/\/|\\/, 2).join(path.sep); // '00-atoms/03-controls/00-button' -> '00-atoms/03-controls' - } this.fileExtension = pathObj.ext; // '.mustache' // this is the unique name, subDir + fileName (sans extension) - this.name = ''; - if (info.hasDir && info.dirLevel > 2) { - let variant = ''; - - if (this.fileName.indexOf('~') !== -1) { - variant = '-' + this.fileName.split('~')[1]; - } - this.name = this.subdir.replace(/[\/\\]/g, '-') + variant; - } else { - this.name = - this.subdir.replace(/[\/\\]/g, '-') + - '-' + - this.fileName.replace('~', '-'); // '00-atoms-00-global-00-colors' - } + // '00-atoms-00-global-00-colors' + this.name = `${info.shortNotation}-${this.fileName.replace('~', '-')}`; // the JSON used to render values in the pattern this.jsonFileData = data || {}; // strip leading "00-" from the file name and flip tildes to dashes this.patternBaseName = this.fileName - .replace(patternPrefixMatcher, '') + .replace(prefixMatcher, '') .replace('~', '-'); // 'colors' - // Fancy name. No idea how this works. 'Colors' - this.patternName = this.patternBaseName - .split('-') - .reduce(function(val, working) { - return ( - val.charAt(0).toUpperCase() + - val.slice(1) + - ' ' + - working.charAt(0).toUpperCase() + - working.slice(1) - ); - }, '') - .trim(); //this is the display name for the ui. strip numeric + hyphen prefixes + // Fancy name - Uppercase letters of pattern name partials. + // global-colors -> 'Global Colors' + // this is the display name for the ui. strip numeric + hyphen prefixes + this.patternName = _.startCase(this.patternBaseName); //00-atoms if needed - this.patternType = this.getDirLevel(0); + this.patternType = this.getDirLevel(0, info); // the top-level pattern group this pattern belongs to. 'atoms' - this.patternGroup = this.patternType.replace(patternPrefixMatcher, ''); + this.patternGroup = this.patternType.replace(prefixMatcher, ''); //00-colors if needed - this.patternSubType = this.getDirLevel(1); + this.patternSubType = this.getDirLevel(1, info); // the sub-group this pattern belongs to. - this.patternSubGroup = this.patternSubType.replace(patternPrefixMatcher, ''); // 'global' + this.patternSubGroup = this.patternSubType.replace(prefixMatcher, ''); // 'global' // the joined pattern group and subgroup directory - this.flatPatternPath = - info.hasDir && info.dirLevel > 2 - ? this.subdir - .replace(/[/\\]/g, '-') - .replace(new RegExp('-' + info.dir + '$'), '') - : this.subdir.replace(/[\/\\]/g, '-'); // '00-atoms-00-global' + this.flatPatternPath = info.shortNotation; // '00-atoms-00-global' // calculated path from the root of the public directory to the generated // (rendered!) html file for this pattern, to be shown in the iframe - this.patternLink = this.patternSectionSubtype - ? `$${this.name}/index.html` - : patternlab + this.patternLink = patternlab ? this.getPatternLink(patternlab, 'rendered') : null; @@ -112,11 +81,25 @@ const Pattern = function(relPath, data, patternlab) { // Let's calculate the verbose name ahead of time! We don't use path.sep here // on purpose. This isn't a file name! - this.verbosePartial = - this.subdir.split(path.sep).join('/') + '/' + this.fileName; + this.verbosePartial = `${info.shortNotation.split('-').join('/')}/${ + this.fileName + }`; - this.isPattern = true; + /** + * Definition of flat pattern: + * The flat pattern is a high level pattern which is attached directly to + * the main root folder or to a root directory. + * --- This --- + * root + * flatpattern + * --- OR That --- + * root + * molecules + * flatpattern + */ this.isFlatPattern = this.patternGroup === this.patternSubGroup; + + this.isPattern = true; this.patternState = ''; this.template = ''; this.patternPartialCode = ''; @@ -218,16 +201,55 @@ Pattern.prototype = { return this.engine.findPartial(partialString); }, - getDirLevel: function(level) { + getDirLevel: function(level, pathInfo) { const items = this.subdir.split(path.sep); + pathInfo.patternHasOwnDir && items.pop(); if (items[level]) { return items[level]; } else if (items[level - 1]) { return items[level - 1]; } else { - return ''; + // Im Not quite shure about that but its better than empty node + return 'root'; + } + }, + + /** + * Info contains information about pattern structure if it is a nested pattern + * or if it just a subbed folder structure. Its just used for internal purposes. + * Remember every pattern infomarion based on "this.*" will be used by other functions + * + * @param pathObj path.parse() object containing usefull path information + */ + getPatternInfo: pathObj => { + const info = { + // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors + patternHasOwnDir: + path.basename(pathObj.dir).replace(prefixMatcher, '') === + pathObj.name.replace(prefixMatcher, '') || + path.basename(pathObj.dir).replace(prefixMatcher, '') === + pathObj.name.split('~')[0].replace(prefixMatcher, ''), + }; + + info.dir = info.patternHasOwnDir ? pathObj.dir.split(path.sep).pop() : ''; + info.dirLevel = pathObj.dir.split(path.sep).filter(s => !!s).length; + + if (info.dirLevel === 0 || (info.dirLevel === 1 && info.patternHasOwnDir)) { + // -> ./ + info.shortNotation = 'root'; + } else if (info.dirLevel === 2 && info.patternHasOwnDir) { + // -> ./folder + info.shortNotation = path.dirname(pathObj.dir); + } else { + // -> ./folder/folder + info.shortNotation = pathObj.dir + .split(/\/|\\/, 2) + .join('-') + .replace(new RegExp(`-${info.dir}$`), ''); } + + return info; }, }; @@ -241,7 +263,7 @@ Pattern.createEmpty = function(customProps, patternlab) { if (customProps.relPath) { relPath = customProps.relPath; } else if (customProps.subdir && customProps.filename) { - relPath = customProps.subdir + path.sep + customProps.filename; + relPath = path.join(customProps.subdir, customProps.filename); } } diff --git a/packages/core/src/lib/ui_builder.js b/packages/core/src/lib/ui_builder.js index 5dcb36986..8b92b656c 100644 --- a/packages/core/src/lib/ui_builder.js +++ b/packages/core/src/lib/ui_builder.js @@ -3,8 +3,7 @@ const path = require('path'); const _ = require('lodash'); -const of = require('./object_factory'); -const Pattern = of.Pattern; +const Pattern = require('./object_factory').Pattern; const logger = require('./log'); const uikitExcludePattern = require('./uikitExcludePattern'); @@ -57,7 +56,7 @@ const ui_builder = function() { //add all if it does not exist yet if (!patternlab.viewAllPaths[pattern.patternGroup].all) { - patternlab.viewAllPaths[pattern.patternGroup].all = pattern.patternType; + patternlab.viewAllPaths[pattern.patternGroup].all = pattern.patternGroup; } } @@ -139,7 +138,7 @@ const ui_builder = function() { ]; if (docPattern) { docPattern.isDocPattern = true; - docPattern.order = -Number.MAX_SAFE_INTEGER; + docPattern.order = Number.MIN_SAFE_INTEGER; return docPattern; } @@ -147,21 +146,20 @@ const ui_builder = function() { docPattern = new Pattern.createEmpty( { name: pattern.flatPatternPath, - patternName: isSubtypePattern - ? pattern.patternSubGroup - : pattern.patternGroup, + patternName: _.startCase( + isSubtypePattern ? pattern.patternSubGroup : pattern.patternGroup + ), patternDesc: '', - patternPartial: - 'viewall-' + - pattern.patternGroup + - (isSubtypePattern ? '-' + pattern.patternSubGroup : ''), + patternPartial: `viewall-${pattern.patternGroup}${ + isSubtypePattern ? '-' + pattern.patternSubGroup : '' + }`, patternSectionSubtype: isSubtypePattern, - patternLink: pattern.flatPatternPath + path.sep + 'index.html', + patternLink: path.join(pattern.flatPatternPath, 'index.html'), isPattern: false, engine: null, flatPatternPath: pattern.flatPatternPath, isDocPattern: true, - order: -Number.MAX_SAFE_INTEGER, + order: Number.MIN_SAFE_INTEGER, }, patternlab ); @@ -177,9 +175,7 @@ const ui_builder = function() { function addPatternType(patternlab, pattern) { patternlab.patternTypes.push({ patternTypeLC: pattern.patternGroup.toLowerCase(), - patternTypeUC: - pattern.patternGroup.charAt(0).toUpperCase() + - pattern.patternGroup.slice(1), + patternTypeUC: _.startCase(pattern.patternGroup), patternType: pattern.patternType, patternTypeDash: pattern.patternGroup, //todo verify patternTypeItems: [], @@ -238,9 +234,7 @@ const ui_builder = function() { function addPatternSubType(patternlab, pattern) { const newSubType = { patternSubtypeLC: pattern.patternSubGroup.toLowerCase(), - patternSubtypeUC: - pattern.patternSubGroup.charAt(0).toUpperCase() + - pattern.patternSubGroup.slice(1), + patternSubtypeUC: _.startCase(pattern.patternSubGroup), patternSubtype: pattern.patternSubType, patternSubtypeDash: pattern.patternSubGroup, //todo verify patternSubtypeItems: [], @@ -258,31 +252,14 @@ const ui_builder = function() { * Creates a patternSubTypeItem object from a pattern * This is a menu item you click on * @param pattern - the pattern to derive the subtypeitem from - * @returns {{patternPartial: string, patternName: (*|string), patternState: string, patternSrcPath: string, patternPath: string}} + * @returns {{patternPartial: string, patternName: (*|string), patternState: string, patternPath: string}} */ function createPatternSubTypeItem(pattern) { - let patternPath = ''; - if (pattern.isFlatPattern) { - patternPath = - pattern.flatPatternPath + - '-' + - pattern.fileName + - '/' + - pattern.flatPatternPath + - '-' + - pattern.fileName + - '.html'; - } else { - patternPath = - pattern.flatPatternPath + '/' + pattern.flatPatternPath + '.html'; - } - return { patternPartial: pattern.patternPartial, patternName: pattern.patternName, patternState: pattern.patternState, - patternSrcPath: encodeURI(pattern.subdir + '/' + pattern.fileName), - patternPath: patternPath, + patternPath: pattern.patternLink, order: pattern.order, }; } @@ -336,18 +313,16 @@ const ui_builder = function() { ); } - if (!patternType.patternItems) { - patternType.patternItems = []; - } + patternType.patternItems = patternType.patternItems || []; if (isViewAllVariant) { if (!pattern.isFlatPattern) { //todo: it'd be nice if we could get this into createPatternSubTypeItem someday patternType.patternItems.push({ - patternPartial: 'viewall-' + pattern.patternGroup + '-all', - patternName: 'View All', - patternPath: encodeURI(pattern.patternType + '/index.html'), - order: -Number.MAX_SAFE_INTEGER, + patternPartial: `viewall-${pattern.patternGroup}-all`, + patternName: `View All ${_.startCase(pattern.patternGroup)}`, + patternPath: encodeURI(pattern.patternGroup + '/index.html'), + order: Number.MIN_SAFE_INTEGER, }); } } else { @@ -454,7 +429,7 @@ const ui_builder = function() { } //continue building navigation for nested patterns - if (pattern.patternGroup !== pattern.patternSubGroup) { + if (!pattern.isFlatPattern) { if ( !groupedPatterns.patternGroups[pattern.patternGroup][ pattern.patternSubGroup @@ -545,6 +520,7 @@ const ui_builder = function() { const styleGuideExcludes = patternlab.config.styleGuideExcludes || patternlab.config.styleguideExcludes; + const subTypePromises = _.map( _.values(patternGroup), (patternSubtypes, patternSubtype, originalPatternGroup) => { @@ -609,9 +585,10 @@ const ui_builder = function() { path.join( process.cwd(), uikit.outputDir, - paths.public.patterns + - p.flatPatternPath + - '/index.html' + path.join( + `${paths.public.patterns}${p.flatPatternPath}`, + 'index.html' + ) ), mainPageHeadHtml + viewAllHTML + footerHTML ); @@ -667,9 +644,10 @@ const ui_builder = function() { path.join( process.cwd(), uikit.outputDir, - paths.public.patterns + - anyPatternOfType.patternType + - '/index.html' + path.join( + `${paths.public.patterns}${patternType}`, + 'index.html' + ) ), mainPageHeadHtml + viewAllHTML + footerHTML ); @@ -740,7 +718,7 @@ const ui_builder = function() { const paths = patternlab.config.paths; const uikitPromises = _.map(patternlab.uikits, uikit => { - //determine which patterns should be included in the front-end rendering + // determine which patterns should be included in the front-end rendering const styleguidePatterns = groupPatterns(patternlab, uikit); return new Promise(resolve => { diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js index 910c02d89..c41d3ba6e 100644 --- a/packages/core/test/object_factory_tests.js +++ b/packages/core/test/object_factory_tests.js @@ -79,8 +79,8 @@ tap.test( path.sep + 'colors.mustache' ); - test.equals(p.name, '00-atoms-00-global'); - test.equals(p.subdir, '00-atoms' + path.sep + '00-global'); + test.equals(p.name, '00-atoms-00-global-00-colors'); + test.equals(p.subdir, path.join('00-atoms', '00-global', '00-colors')); test.equals(p.fileName, 'colors'); test.equals(p.fileExtension, '.mustache'); test.equals(p.jsonFileData.d, 123); @@ -88,10 +88,12 @@ tap.test( test.equals(p.patternName, 'Colors'); test.equals( p.getPatternLink(pl), - '00-atoms-00-global' + path.sep + '00-atoms-00-global.rendered.html' + '00-atoms-00-global-00-colors' + + path.sep + + '00-atoms-00-global-00-colors.rendered.html' ); test.equals(p.patternGroup, 'atoms'); - test.equals(p.patternSubGroup, 'global'); //because of p.info.hasDir + test.equals(p.patternSubGroup, 'global'); test.equals(p.flatPatternPath, '00-atoms-00-global'); test.equals(p.patternPartial, 'atoms-colors'); test.equals(p.template, ''); @@ -106,14 +108,17 @@ tap.test( ); tap.test('test Pattern name for variants correctly initialzed', function(test) { - var p1 = new Pattern('00-atoms/00-global/colors~variant.mustache', { - d: 123, - }); - var p2 = new Pattern('00-atoms/00-global/colors~variant-minus.json', { + var p1 = new Pattern('00-atoms/00-global/00-colors/colors~variant.mustache', { d: 123, }); - test.equals(p1.name, '00-atoms-00-global-colors-variant'); - test.equals(p2.name, '00-atoms-00-global-colors-variant-minus'); + var p2 = new Pattern( + '00-atoms/00-global/00-colors/colors~variant-minus.json', + { + d: 123, + } + ); + test.equals(p1.name, '00-atoms-00-global-00-colors-variant'); + test.equals(p2.name, '00-atoms-00-global-00-colors-variant-minus'); test.end(); }); @@ -205,20 +210,11 @@ tap.test( d: 123, }); test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 2 }), '00-atoms'); - test.equals( - p.getDirLevel(1, { hasDir: true, dirLevel: 2 }), - '00-colors-alt' - ); + test.equals(p.getDirLevel(1, { hasDir: true, dirLevel: 2 }), '00-colors'); test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 2 }), ''); var p = new Pattern('00-colors-alt/colors-alt.mustache', { d: 123 }); - test.equals( - p.getDirLevel(0, { hasDir: true, dirLevel: 1 }), - '00-colors-alt' - ); - test.equals( - p.getDirLevel(1, { hasDir: true, dirLevel: 1 }), - '00-colors-alt' - ); + test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 1 }), ''); + test.equals(p.getDirLevel(1, { hasDir: true, dirLevel: 1 }), ''); test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 1 }), ''); test.end(); } diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index af3d0bf26..15e89203d 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -415,7 +415,7 @@ class Nav extends BaseComponent { return ( {patternSubtype.patternSubtypeItems} From edc4b0cb22b78d1019395c3f228b59ec230ca03d Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Sun, 12 Apr 2020 21:35:29 +0200 Subject: [PATCH 003/330] Various changes to file and pattern creation - Fixed test cases incorrect - Fixed view all pages not generated - Fixed view all page could not be loaded - Fixed pattern ordering - Fixed subfolder patterns have invalid data - Fixed subfolder patterns are not rendered properly --- .prettierrc | 3 +- packages/core/patternlab-config.json | 4 + packages/core/src/lib/object_factory.js | 198 +++++--- packages/core/src/lib/parameter_hunter.js | 2 +- packages/core/src/lib/ui_builder.js | 447 +++++++++--------- packages/core/test/object_factory_tests.js | 124 +++-- packages/core/test/ui_builder_tests.js | 113 +++-- packages/edition-node/patternlab-config.json | 4 + .../engine-mustache/lib/engine_mustache.js | 24 +- .../scss/04-components/_pattern-category.scss | 11 +- .../src/scripts/components/pl-nav/pl-nav.js | 2 +- 11 files changed, 526 insertions(+), 406 deletions(-) diff --git a/.prettierrc b/.prettierrc index c1a6f6671..d81dbaeb5 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,5 @@ { "singleQuote": true, - "trailingComma": "es5" + "trailingComma": "es5", + "endOfLine": "auto" } diff --git a/packages/core/patternlab-config.json b/packages/core/patternlab-config.json index 39eed54fd..265e98b65 100644 --- a/packages/core/patternlab-config.json +++ b/packages/core/patternlab-config.json @@ -75,6 +75,10 @@ "patternExportPatternPartials": [], "patternExportPreserveDirectoryStructure": true, "patternExportRaw": false, + "patternTranslations": { + "view-all": "View all {groupName}", + "root-name": "Root" + }, "serverOptions": { "wait": 1000 }, diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 83524a9c7..90c30112d 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -1,18 +1,27 @@ 'use strict'; -const patternEngines = require('./pattern_engines'); + +const _ = require('lodash'); const path = require('path'); +const patternEngines = require('./pattern_engines'); -// patternPrefixMatcher is intended to match the leading maybe-underscore, +// prefixMatcher is intended to match the leading maybe-underscore, // zero or more digits, and maybe-dash at the beginning of a pattern file name we can hack them // off and get at the good part. -const patternPrefixMatcher = /^_?(\d+-)?/; +const prefixMatcher = /^_?(\d+-)?/; -// Pattern properties /** - * Pattern constructor + * Pattern constructor / Pattern properties + * + * Before changing functionalities of the pattern object please read the following pull requests + * to get more details about the behavior of the folder structure + * https://github.com/pattern-lab/patternlab-node/pull/992 + * https://github.com/pattern-lab/patternlab-node/pull/1016 + * * @constructor */ const Pattern = function(relPath, data, patternlab) { + this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' + /** * We expect relPath to be the path of the pattern template, relative to the * root of the pattern tree. Parse out the path parts and save the useful ones. @@ -20,40 +29,26 @@ const Pattern = function(relPath, data, patternlab) { * @param {data} The JSON used to render values in the pattern. * @param {patternlab} rendered html files for the pattern */ - const pathObj = path.parse(path.normalize(relPath)); - const info = {}; - // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors - info.hasDir = - path.basename(pathObj.dir).replace(patternPrefixMatcher, '') === - pathObj.name.replace(patternPrefixMatcher, '') || - path.basename(pathObj.dir).replace(patternPrefixMatcher, '') === - pathObj.name.split('~')[0].replace(patternPrefixMatcher, ''); - - info.dir = info.hasDir ? pathObj.dir.split(path.sep).pop() : ''; - info.dirLevel = pathObj.dir.split(path.sep).length; + const pathObj = path.parse(this.relPath); + + const info = this.getPatternInfo(pathObj, patternlab); - this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' this.fileName = pathObj.name; // '00-colors' this.subdir = pathObj.dir; // '00-atoms/00-global' - if ((this.subdir.match(/\w(?=\\)|\w(?=\/)/g) || []).length > 1) { - this.subdir = this.subdir.split(/\/|\\/, 2).join(path.sep); // '00-atoms/03-controls/00-button' -> '00-atoms/03-controls' - } this.fileExtension = pathObj.ext; // '.mustache' - // this is the unique name, subDir + fileName (sans extension) - this.name = ''; - if (info.hasDir && info.dirLevel > 2) { - let variant = ''; - - if (this.fileName.indexOf('~') !== -1) { - variant = '-' + this.fileName.split('~')[1]; - } - this.name = this.subdir.replace(/[\/\\]/g, '-') + variant; + // TODO: Remove if when droping ordering by prefix and keep else code + if (info.patternHasOwnDir) { + // Since there is still the requirement of having the numbers provided for sorting + // this will be required to keep the folder prefix and the variant name + // /00-atoms/00-global/00-colors/colors~varian.hbs + // -> 00-atoms-00-global-00-colors + this.name = `${info.shortNotation}-${path.parse(pathObj.dir).base}${ + this.fileName.indexOf('~') !== -1 ? '-' + this.fileName.split('~')[1] : '' + }`; } else { - this.name = - this.subdir.replace(/[\/\\]/g, '-') + - '-' + - this.fileName.replace('~', '-'); // '00-atoms-00-global-00-colors' + // this is the unique name, subDir + fileName (sans extension) + this.name = `${info.shortNotation}-${this.fileName.replace('~', '-')}`; } // the JSON used to render values in the pattern @@ -61,48 +56,32 @@ const Pattern = function(relPath, data, patternlab) { // strip leading "00-" from the file name and flip tildes to dashes this.patternBaseName = this.fileName - .replace(patternPrefixMatcher, '') + .replace(prefixMatcher, '') .replace('~', '-'); // 'colors' - // Fancy name. No idea how this works. 'Colors' - this.patternName = this.patternBaseName - .split('-') - .reduce(function(val, working) { - return ( - val.charAt(0).toUpperCase() + - val.slice(1) + - ' ' + - working.charAt(0).toUpperCase() + - working.slice(1) - ); - }, '') - .trim(); //this is the display name for the ui. strip numeric + hyphen prefixes + // Fancy name - Uppercase letters of pattern name partials. + // global-colors -> 'Global Colors' + // this is the display name for the ui. strip numeric + hyphen prefixes + this.patternName = _.startCase(this.patternBaseName); //00-atoms if needed - this.patternType = this.getDirLevel(0); + this.patternType = this.getDirLevel(0, info); // the top-level pattern group this pattern belongs to. 'atoms' - this.patternGroup = this.patternType.replace(patternPrefixMatcher, ''); + this.patternGroup = this.patternType.replace(prefixMatcher, ''); //00-colors if needed - this.patternSubType = this.getDirLevel(1); + this.patternSubType = this.getDirLevel(1, info); // the sub-group this pattern belongs to. - this.patternSubGroup = this.patternSubType.replace(patternPrefixMatcher, ''); // 'global' + this.patternSubGroup = this.patternSubType.replace(prefixMatcher, ''); // 'global' // the joined pattern group and subgroup directory - this.flatPatternPath = - info.hasDir && info.dirLevel > 2 - ? this.subdir - .replace(/[/\\]/g, '-') - .replace(new RegExp('-' + info.dir + '$'), '') - : this.subdir.replace(/[\/\\]/g, '-'); // '00-atoms-00-global' + this.flatPatternPath = info.shortNotation; // '00-atoms-00-global' // calculated path from the root of the public directory to the generated // (rendered!) html file for this pattern, to be shown in the iframe - this.patternLink = this.patternSectionSubtype - ? `$${this.name}/index.html` - : patternlab + this.patternLink = patternlab ? this.getPatternLink(patternlab, 'rendered') : null; @@ -112,11 +91,24 @@ const Pattern = function(relPath, data, patternlab) { // Let's calculate the verbose name ahead of time! We don't use path.sep here // on purpose. This isn't a file name! - this.verbosePartial = - this.subdir.split(path.sep).join('/') + '/' + this.fileName; + this.verbosePartial = `${info.shortNotation}/${this.fileName}`; + + /** + * Definition of flat pattern: + * The flat pattern is a high level pattern which is attached directly to + * the main root folder or to a root directory. + * --- This --- + * root + * flatpattern + * --- OR That --- + * root + * molecules + * flatpattern + */ + this.isFlatPattern = + this.patternGroup === this.patternSubGroup || !this.patternSubGroup; this.isPattern = true; - this.isFlatPattern = this.patternGroup === this.patternSubGroup; this.patternState = ''; this.template = ''; this.patternPartialCode = ''; @@ -125,7 +117,7 @@ const Pattern = function(relPath, data, patternlab) { this.lineageR = []; this.lineageRIndex = []; this.isPseudoPattern = false; - this.order = Number.MAX_SAFE_INTEGER; + this.order = 0; this.engine = patternEngines.getEngineForPattern(this); /** @@ -218,30 +210,86 @@ Pattern.prototype = { return this.engine.findPartial(partialString); }, - getDirLevel: function(level) { + getDirLevel: function(level, pathInfo) { const items = this.subdir.split(path.sep); + pathInfo.patternHasOwnDir && items.pop(); if (items[level]) { return items[level]; - } else if (items[level - 1]) { - return items[level - 1]; - } else { + } else if (level >= 1) { return ''; + } else { + // Im Not quite shure about that but its better than empty node + // TODO: verify + return pathInfo.patternlab && + pathInfo.patternlab.config.patternTranslations && + pathInfo.patternlab.config.patternTranslations['root-name'] + ? _.kebabCase( + pathInfo.patternlab.config.patternTranslations['root-name'] + ) + : 'root'; + } + }, + + /** + * Info contains information about pattern structure if it is a nested pattern + * or if it just a subbed folder structure. Its just used for internal purposes. + * Remember every pattern infomarion based on "this.*" will be used by other functions + * + * @param pathObj path.parse() object containing usefull path information + */ + getPatternInfo: (pathObj, patternlab) => { + const info = { + // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors + patternlab: patternlab, + patternHasOwnDir: + path.basename(pathObj.dir).replace(prefixMatcher, '') === + pathObj.name.replace(prefixMatcher, '') || + path.basename(pathObj.dir).replace(prefixMatcher, '') === + pathObj.name.split('~')[0].replace(prefixMatcher, ''), + }; + + info.dir = info.patternHasOwnDir ? pathObj.dir.split(path.sep).pop() : ''; + info.dirLevel = pathObj.dir.split(path.sep).filter(s => !!s).length; + + if (info.dirLevel === 0 || (info.dirLevel === 1 && info.patternHasOwnDir)) { + // -> ./ + info.shortNotation = 'root'; + } else if (info.dirLevel === 2 && info.patternHasOwnDir) { + // -> ./folder + info.shortNotation = path.dirname(pathObj.dir); + } else { + // -> ./folder/folder + info.shortNotation = pathObj.dir + .split(/\/|\\/, 2) + .join('-') + .replace(new RegExp(`-${info.dir}$`), ''); + info.verbosePartial = pathObj.dir + .split(/\/|\\/, 2) + .join('/') + .replace(new RegExp(`-${info.dir}$`), ''); } + + return info; }, }; // Pattern static methods -// factory: creates an empty Pattern for miscellaneous internal use, such as -// by list_item_hunter +/** + * factory: creates an empty Pattern for miscellaneous internal use, such as + * by list_item_hunter + * + * @param {Object} customProps Properties to apply to new pattern + * @param {Patternlab} patternlab Current patternlab instance + */ Pattern.createEmpty = function(customProps, patternlab) { let relPath = ''; if (customProps) { if (customProps.relPath) { relPath = customProps.relPath; } else if (customProps.subdir && customProps.filename) { - relPath = customProps.subdir + path.sep + customProps.filename; + relPath = path.join(customProps.subdir, customProps.filename); } } @@ -249,9 +297,11 @@ Pattern.createEmpty = function(customProps, patternlab) { return Object.assign(pattern, customProps); }; -// factory: creates an Pattern object on-demand from a hash; the hash accepts -// parameters that replace the positional parameters that the Pattern -// constructor takes. +/** + * factory: creates an Pattern object on-demand from a hash; the hash accepts + * parameters that replace the positional parameters that the Pattern + * constructor takes. + */ Pattern.create = function(relPath, data, customProps, patternlab) { const newPattern = new Pattern(relPath || '', data || null, patternlab); return Object.assign(newPattern, customProps); diff --git a/packages/core/src/lib/parameter_hunter.js b/packages/core/src/lib/parameter_hunter.js index eeec121dc..aa2ce38dc 100644 --- a/packages/core/src/lib/parameter_hunter.js +++ b/packages/core/src/lib/parameter_hunter.js @@ -248,7 +248,7 @@ const parameter_hunter = function() { //compile this partial immeadiately, essentially consuming it. function findparameters(pattern, patternlab) { if (pattern.parameteredPartials && pattern.parameteredPartials.length > 0) { - logger.debug(`processing patternParameters for ${pattern.partialName}`); + logger.debug(`processing patternParameters for ${pattern.patternName}`); return pattern.parameteredPartials.reduce((previousPromise, pMatch) => { return previousPromise diff --git a/packages/core/src/lib/ui_builder.js b/packages/core/src/lib/ui_builder.js index 5dcb36986..148a872aa 100644 --- a/packages/core/src/lib/ui_builder.js +++ b/packages/core/src/lib/ui_builder.js @@ -3,12 +3,11 @@ const path = require('path'); const _ = require('lodash'); -const of = require('./object_factory'); -const Pattern = of.Pattern; +const Pattern = require('./object_factory').Pattern; const logger = require('./log'); const uikitExcludePattern = require('./uikitExcludePattern'); -//these are mocked in unit tests, so let them be overridden +// these are mocked in unit tests, so let them be overridden let render = require('./render'); //eslint-disable-line prefer-const let fs = require('fs-extra'); //eslint-disable-line prefer-const let buildFooter = require('./buildFooter'); //eslint-disable-line prefer-const @@ -26,7 +25,7 @@ const ui_builder = function() { patternlab.patternPaths[pattern.patternGroup] = {}; } - //only add real patterns + // only add real patterns if (pattern.isPattern && !pattern.isDocPattern) { patternlab.patternPaths[pattern.patternGroup][pattern.patternBaseName] = pattern.name; @@ -44,20 +43,18 @@ const ui_builder = function() { } if ( - !patternlab.viewAllPaths[pattern.patternGroup][pattern.patternSubGroup] + !patternlab.viewAllPaths[pattern.patternGroup][pattern.patternSubGroup] && + pattern.patternSubGroup ) { + // note these retain any number prefixes if present, because these paths match the filesystem patternlab.viewAllPaths[pattern.patternGroup][ pattern.patternSubGroup - ] = {}; + ] = `${pattern.patternType}-${pattern.patternSubType}`; } - //note these retain any number prefixes if present, because these paths match the filesystem - patternlab.viewAllPaths[pattern.patternGroup][pattern.patternSubGroup] = - pattern.patternType + '-' + pattern.patternSubType; - - //add all if it does not exist yet + // add all if it does not exist yet if (!patternlab.viewAllPaths[pattern.patternGroup].all) { - patternlab.viewAllPaths[pattern.patternGroup].all = pattern.patternType; + patternlab.viewAllPaths[pattern.patternGroup].all = pattern.patternGroup; } } @@ -89,7 +86,7 @@ const ui_builder = function() { return true; } - //this is meant to be a homepage that is not present anywhere else + // this is meant to be a homepage that is not present anywhere else isOmitted = pattern.patternPartial === patternlab.config.defaultPattern; if (isOmitted) { logger.info( @@ -99,7 +96,7 @@ const ui_builder = function() { return true; } - //this pattern is contained with a directory prefixed with an underscore (a handy way to hide whole directories from the nav + // this pattern is contained with a directory prefixed with an underscore (a handy way to hide whole directories from the nav isOmitted = pattern.relPath.charAt(0) === '_' || pattern.relPath.indexOf(path.sep + '_') > -1; @@ -110,7 +107,7 @@ const ui_builder = function() { return true; } - //this pattern is a head or foot pattern + // this pattern is a head or foot pattern isOmitted = pattern.isMetaPattern; if (isOmitted) { logger.info( @@ -119,7 +116,7 @@ const ui_builder = function() { return true; } - //yay, let's include this on the front end + // yay, let's include this on the front end return isOmitted; } @@ -131,7 +128,7 @@ const ui_builder = function() { * @returns the found or created pattern object */ function injectDocumentationBlock(pattern, patternlab, isSubtypePattern) { - //first see if loadPattern processed one already + // first see if loadPattern processed one already let docPattern = patternlab.subtypePatterns[ pattern.patternGroup + @@ -139,29 +136,31 @@ const ui_builder = function() { ]; if (docPattern) { docPattern.isDocPattern = true; - docPattern.order = -Number.MAX_SAFE_INTEGER; + docPattern.order = Number.MIN_SAFE_INTEGER; return docPattern; } - //if not, create one now + // if not, create one now docPattern = new Pattern.createEmpty( { name: pattern.flatPatternPath, - patternName: isSubtypePattern - ? pattern.patternSubGroup - : pattern.patternGroup, + patternName: _.startCase( + isSubtypePattern ? pattern.patternSubGroup : pattern.patternGroup + ), patternDesc: '', - patternPartial: - 'viewall-' + - pattern.patternGroup + - (isSubtypePattern ? '-' + pattern.patternSubGroup : ''), - patternSectionSubtype: isSubtypePattern, - patternLink: pattern.flatPatternPath + path.sep + 'index.html', + patternPartial: `viewall-${pattern.patternGroup}-${ + isSubtypePattern ? pattern.patternSubGroup : 'all' + }`, + patternSectionSubtype: true, + patternLink: path.join( + isSubtypePattern ? pattern.flatPatternPath : pattern.patternGroup, + 'index.html' + ), isPattern: false, engine: null, flatPatternPath: pattern.flatPatternPath, isDocPattern: true, - order: -Number.MAX_SAFE_INTEGER, + order: Number.MIN_SAFE_INTEGER, }, patternlab ); @@ -177,9 +176,7 @@ const ui_builder = function() { function addPatternType(patternlab, pattern) { patternlab.patternTypes.push({ patternTypeLC: pattern.patternGroup.toLowerCase(), - patternTypeUC: - pattern.patternGroup.charAt(0).toUpperCase() + - pattern.patternGroup.slice(1), + patternTypeUC: _.startCase(pattern.patternGroup), patternType: pattern.patternType, patternTypeDash: pattern.patternGroup, //todo verify patternTypeItems: [], @@ -238,9 +235,7 @@ const ui_builder = function() { function addPatternSubType(patternlab, pattern) { const newSubType = { patternSubtypeLC: pattern.patternSubGroup.toLowerCase(), - patternSubtypeUC: - pattern.patternSubGroup.charAt(0).toUpperCase() + - pattern.patternSubGroup.slice(1), + patternSubtypeUC: _.startCase(pattern.patternSubGroup), patternSubtype: pattern.patternSubType, patternSubtypeDash: pattern.patternSubGroup, //todo verify patternSubtypeItems: [], @@ -258,32 +253,16 @@ const ui_builder = function() { * Creates a patternSubTypeItem object from a pattern * This is a menu item you click on * @param pattern - the pattern to derive the subtypeitem from - * @returns {{patternPartial: string, patternName: (*|string), patternState: string, patternSrcPath: string, patternPath: string}} + * @returns {{patternPartial: string, patternName: (*|string), patternState: string, patternPath: string}} */ function createPatternSubTypeItem(pattern) { - let patternPath = ''; - if (pattern.isFlatPattern) { - patternPath = - pattern.flatPatternPath + - '-' + - pattern.fileName + - '/' + - pattern.flatPatternPath + - '-' + - pattern.fileName + - '.html'; - } else { - patternPath = - pattern.flatPatternPath + '/' + pattern.flatPatternPath + '.html'; - } - return { patternPartial: pattern.patternPartial, patternName: pattern.patternName, patternState: pattern.patternState, - patternSrcPath: encodeURI(pattern.subdir + '/' + pattern.fileName), - patternPath: patternPath, - order: pattern.order, + patternPath: pattern.patternLink, + name: pattern.name, + order: Number(pattern.order) || 0, // Failsave is someone entered a string }; } @@ -309,7 +288,8 @@ const ui_builder = function() { patternPath: encodeURI(pattern.flatPatternPath + '/index.html'), patternType: pattern.patternType, patternSubtype: pattern.patternSubtype, - order: 0, + name: pattern.flatPatternPath, + order: Number.MAX_SAFE_INTEGER, }; } else { newSubTypeItem = createPatternSubTypeItem(pattern); @@ -336,20 +316,22 @@ const ui_builder = function() { ); } - if (!patternType.patternItems) { - patternType.patternItems = []; - } - + patternType.patternItems = patternType.patternItems || []; if (isViewAllVariant) { - if (!pattern.isFlatPattern) { - //todo: it'd be nice if we could get this into createPatternSubTypeItem someday - patternType.patternItems.push({ - patternPartial: 'viewall-' + pattern.patternGroup + '-all', - patternName: 'View All', - patternPath: encodeURI(pattern.patternType + '/index.html'), - order: -Number.MAX_SAFE_INTEGER, - }); - } + patternType.patternItems.push({ + patternPartial: `viewall-${pattern.patternGroup}-all`, + patternName: + patternlab.config.patternTranslations && + patternlab.config.patternTranslations['view-all'] + ? patternlab.config.patternTranslations['view-all'].replace( + '{groupName}', + _.startCase(pattern.patternGroup) + ) + : `View all ${_.startCase(pattern.patternGroup)}`, + patternPath: encodeURI(pattern.patternGroup + '/index.html'), + name: pattern.patternGroup, + order: Number.MAX_SAFE_INTEGER, + }); } else { patternType.patternItems.push(createPatternSubTypeItem(pattern)); } @@ -359,14 +341,6 @@ const ui_builder = function() { ]); } - // function getPatternItems(patternlab, patternType) { - // var patternType = _.find(patternlab.patternTypes, ['patternTypeLC', patternType]); - // if (patternType) { - // return patternType.patternItems; - // } - // return []; - // } - /** * Sorts patterns based on order property found within pattern markdown, falling back on name. * @param patternsArray - patterns to sort @@ -385,7 +359,7 @@ const ui_builder = function() { aOrder = Number.MAX_SAFE_INTEGER; } - //alwasy return a docPattern first + // alwasy return a docPattern first if (a.isDocPattern && !b.isDocPattern) { return -1; } @@ -394,8 +368,8 @@ const ui_builder = function() { return 1; } - //use old alphabetical ordering if we have nothing else to use - //pattern.order will be Number.MAX_SAFE_INTEGER if never defined by markdown, or markdown parsing fails + // use old alphabetical ordering if we have nothing else to use + // pattern.order will be Number.MAX_SAFE_INTEGER if never defined by markdown, or markdown parsing fails if ( aOrder === Number.MAX_SAFE_INTEGER && bOrder === Number.MAX_SAFE_INTEGER @@ -408,7 +382,7 @@ const ui_builder = function() { } } - //if we get this far, we can sort safely + // if we get this far, we can sort safely if (aOrder && bOrder) { if (aOrder > bOrder) { return 1; @@ -433,7 +407,7 @@ const ui_builder = function() { }; _.forEach(patternlab.patterns, function(pattern) { - //ignore patterns we can omit from rendering directly + // ignore patterns we can omit from rendering directly pattern.omitFromStyleguide = isPatternExcluded( pattern, patternlab, @@ -447,14 +421,12 @@ const ui_builder = function() { groupedPatterns.patternGroups[pattern.patternGroup] = {}; pattern.isSubtypePattern = false; addPatternType(patternlab, pattern); - - //todo: Pattern Type View All and Documentation - //groupedPatterns.patternGroups[pattern.patternGroup]['viewall-' + pattern.patternGroup] = injectDocumentationBlock(pattern, patternlab, false); addPatternItem(patternlab, pattern, true); + addToViewAllPaths(patternlab, pattern); } - //continue building navigation for nested patterns - if (pattern.patternGroup !== pattern.patternSubGroup) { + // continue building navigation for nested patterns + if (!pattern.isFlatPattern) { if ( !groupedPatterns.patternGroups[pattern.patternGroup][ pattern.patternSubGroup @@ -491,6 +463,23 @@ const ui_builder = function() { return groupedPatterns; } + /** + * Search all flat patterns of a specific pattern type + * + * @param {Patternlab} patternlab Current patternlab instance + * @param {String} patternType indicator which patterns to search for + */ + function getFlatPatternItems(patternlab, patternType) { + const patterns = _.filter( + patternlab.patterns, + pattern => pattern.patternGroup === patternType && pattern.isFlatPattern + ); + if (patterns) { + return sortPatterns(patterns); + } + return []; + } + /** * Takes a set of patterns and builds a viewall HTML page for them * Used by the type and subtype viewall sets @@ -501,15 +490,15 @@ const ui_builder = function() { */ function buildViewAllHTML(patternlab, patterns, patternPartial, uikit) { return render( - Pattern.createEmpty({ extendedTemplate: uikit.viewAll }), + Pattern.createEmpty({ extendedTemplate: uikit.viewAll }, patternlab), { - //data + // data partials: patterns, patternPartial: 'viewall-' + patternPartial, cacheBuster: patternlab.cacheBuster, }, { - //templates + // templates patternSection: uikit.patternSection, patternSectionSubtype: uikit.patternSectionSubType, } @@ -534,57 +523,59 @@ const ui_builder = function() { ) { const paths = patternlab.config.paths; let patterns = []; - let writeViewAllFile = true; - //loop through the grouped styleguide patterns, building at each level + // loop through the grouped styleguide patterns, building at each level const allPatternTypePromises = _.map( styleguidePatterns.patternGroups, (patternGroup, patternType) => { let typePatterns = []; let styleguideTypePatterns = []; - const styleGuideExcludes = - patternlab.config.styleGuideExcludes || - patternlab.config.styleguideExcludes; + const styleGuideExcludes = patternlab.config.styleGuideExcludes || []; + + /** + * View all pages for subgroups + */ const subTypePromises = _.map( _.values(patternGroup), (patternSubtypes, patternSubtype, originalPatternGroup) => { let p; - const samplePattern = _.find(patternSubtypes, st => { - return !st.patternPartial.startsWith('viewall-'); - }); + const samplePattern = _.find( + patternSubtypes, + st => !st.patternPartial.startsWith('viewall-') + ); const patternName = Object.keys( _.values(originalPatternGroup)[patternSubtype] )[1]; const patternPartial = patternType + '-' + samplePattern.patternSubType; - //do not create a viewall page for flat patterns + // do not create a viewall page for flat patterns if (patternType === patternName) { - writeViewAllFile = false; logger.debug( `skipping ${patternType} as flat patterns do not have view all pages` ); return Promise.resolve(); } - //render the footer needed for the viewall template + // render the footer needed for the viewall template return buildFooter(patternlab, `viewall-${patternPartial}`, uikit) .then(footerHTML => { - //render the viewall template by finding these smallest subtype-grouped patterns + // render the viewall template by finding these smallest subtype-grouped patterns const subtypePatterns = sortPatterns(_.values(patternSubtypes)); - //determine if we should write at this time by checking if these are flat patterns or grouped patterns + // determine if we should write at this time by checking if these are flat patterns or grouped patterns p = _.find(subtypePatterns, function(pat) { return pat.isDocPattern; }); - //determine if we should omit this subpatterntype completely from the viewall page + // determine if we should omit this subpatterntype completely from the viewall page const omitPatternType = styleGuideExcludes && styleGuideExcludes.length && - _.some(styleGuideExcludes, function(exclude) { - return exclude === patternType + '/' + patternName; - }); + _.some( + styleGuideExcludes, + exclude => exclude === `${patternType}/${patternName}` + ); if (omitPatternType) { logger.debug( `Omitting ${patternType}/${patternName} from building a viewall page because its patternSubGroup is specified in styleguideExcludes.` @@ -597,7 +588,7 @@ const ui_builder = function() { typePatterns = typePatterns.concat(subtypePatterns); - //render the viewall template for the subtype + // render the viewall template for the subtype return buildViewAllHTML( patternlab, subtypePatterns, @@ -609,9 +600,10 @@ const ui_builder = function() { path.join( process.cwd(), uikit.outputDir, - paths.public.patterns + - p.flatPatternPath + - '/index.html' + path.join( + `${paths.public.patterns}${p.flatPatternPath}`, + 'index.html' + ) ), mainPageHeadHtml + viewAllHTML + footerHTML ); @@ -621,96 +613,92 @@ const ui_builder = function() { logger.error('Error building ViewAllHTML'); }); }) - .then(() => { - //do not create a viewall page for flat patterns - if (!writeViewAllFile || !p) { + .catch(reason => { + console.log(reason); + logger.error('Error building footer HTML'); + }); + } + ); + + /** + * View all pages for goups + */ + return Promise.all(subTypePromises) + .then(() => { + // render the footer needed for the viewall template + return buildFooter(patternlab, `viewall-${patternType}-all`, uikit) + .then(footerHTML => { + const sortedFlatPatterns = getFlatPatternItems( + patternlab, + patternType + ); + + // Check if this is a flat pattern group + typePatterns = sortedFlatPatterns.concat(typePatterns); + + // get the appropriate patternType + const anyPatternOfType = _.find(typePatterns, function(pat) { + return pat.patternType && pat.patternType !== ''; + }); + + if (!anyPatternOfType) { logger.debug( `skipping ${patternType} as flat patterns do not have view all pages` ); - return Promise.resolve(); + return Promise.resolve([]); } - //render the footer needed for the viewall template - return buildFooter( + // render the viewall template for the type + return buildViewAllHTML( patternlab, - 'viewall-' + patternType + '-all', + typePatterns, + patternType, uikit ) - .then(footerHTML => { - //add any flat patterns - //todo this isn't quite working yet - //typePatterns = typePatterns.concat(getPatternItems(patternlab, patternType)); - - //get the appropriate patternType - const anyPatternOfType = _.find(typePatterns, function( - pat - ) { - return pat.patternType && pat.patternType !== ''; - }); - - if (!anyPatternOfType) { + .then(viewAllHTML => { + fs.outputFileSync( + path.join( + process.cwd(), + uikit.outputDir, + path.join( + `${paths.public.patterns}${patternType}`, + 'index.html' + ) + ), + mainPageHeadHtml + viewAllHTML + footerHTML + ); + + // determine if we should omit this patterntype completely from the viewall page + const omitPatternType = + styleGuideExcludes && + styleGuideExcludes.length && + _.some(styleGuideExcludes, function(exclude) { + return exclude === patternType; + }); + if (omitPatternType) { logger.debug( - `skipping ${patternType} as flat patterns do not have view all pages` + `Omitting ${patternType} from building a viewall page because its patternGroup is specified in styleguideExcludes.` ); - return Promise.resolve(); + } else { + patterns = sortedFlatPatterns; + patterns = patterns.concat(styleguideTypePatterns); } - - //render the viewall template for the type - return buildViewAllHTML( - patternlab, - typePatterns, - patternType, - uikit - ) - .then(viewAllHTML => { - fs.outputFileSync( - path.join( - process.cwd(), - uikit.outputDir, - paths.public.patterns + - anyPatternOfType.patternType + - '/index.html' - ), - mainPageHeadHtml + viewAllHTML + footerHTML - ); - - //determine if we should omit this patterntype completely from the viewall page - const omitPatternType = - styleGuideExcludes && - styleGuideExcludes.length && - _.some(styleGuideExcludes, function(exclude) { - return exclude === patternType; - }); - if (omitPatternType) { - logger.debug( - `Omitting ${patternType} from building a viewall page because its patternGroup is specified in styleguideExcludes.` - ); - } else { - patterns = patterns.concat(styleguideTypePatterns); - } - return Promise.resolve(patterns); - }) - .catch(reason => { - console.log(reason); - logger.error('Error building ViewAllHTML'); - }); + return Promise.resolve(patterns); }) .catch(reason => { console.log(reason); - logger.error('Error building footerHTML'); + logger.error('Error building ViewAllHTML'); }); }) .catch(reason => { console.log(reason); - logger.error('Error building footer HTML'); + logger.error('Error building footerHTML'); }); - } - ); - - return Promise.all(subTypePromises).catch(reason => { - console.log(reason); - logger.error('Error during buildViewAllPages'); - }); + }) + .catch(reason => { + console.log(reason); + logger.error('Error during buildViewAllPages'); + }); } ); @@ -722,6 +710,8 @@ const ui_builder = function() { /** * Reset any global data we use between builds to guard against double adding things + * + * @param {Patternlab} patternlab Actual patternlab instance */ function resetUIBuilderState(patternlab) { patternlab.patternPaths = {}; @@ -729,8 +719,32 @@ const ui_builder = function() { patternlab.patternTypes = []; } + /** + * Uniques all generated patterns and groups, also adds a group document pattern before + * each group. Used for generating view all page and all its pattern. + * + * @param {[Pattern[]]} allPatterns All generated patterns + * @param {Patternlab} patternlab Actual patternlab instance + */ + function uniqueAllPatterns(allPatterns, patternlab) { + return _.uniq( + _.flatMapDeep( + _.map(allPatterns, patterns => [ + injectDocumentationBlock( + _.find(patterns, p => !p.patternPartial.startsWith('viewall-')), + patternlab, + false + ), + ...patterns, + ]), + pattern => pattern + ) + ); + } + /** * The main entry point for ui_builder + * * @param patternlab - global data store * @returns {Promise} a promise fulfilled when build is complete */ @@ -740,13 +754,13 @@ const ui_builder = function() { const paths = patternlab.config.paths; const uikitPromises = _.map(patternlab.uikits, uikit => { - //determine which patterns should be included in the front-end rendering + // determine which patterns should be included in the front-end rendering const styleguidePatterns = groupPatterns(patternlab, uikit); return new Promise(resolve => { - //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header + // set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header const headerPromise = render( - Pattern.createEmpty({ extendedTemplate: uikit.header }), + Pattern.createEmpty({ extendedTemplate: uikit.header }, patternlab), { cacheBuster: patternlab.cacheBuster, } @@ -762,9 +776,9 @@ const ui_builder = function() { logger.error('error during header render()'); }); - //set the pattern-specific footer by compiling the general-footer with data, and then adding it to the meta footer + // set the pattern-specific footer by compiling the general-footer with data, and then adding it to the meta footer const footerPromise = render( - Pattern.createEmpty({ extendedTemplate: uikit.footer }), + Pattern.createEmpty({ extendedTemplate: uikit.footer }, patternlab), { patternData: '{}', cacheBuster: patternlab.cacheBuster, @@ -782,7 +796,7 @@ const ui_builder = function() { return Promise.all([headerPromise, footerPromise]).then( headFootPromiseResults => { - //build the viewall pages + // build the viewall pages return buildViewAllPages( headFootPromiseResults[0], @@ -791,24 +805,26 @@ const ui_builder = function() { uikit ) .then(allPatterns => { - //todo track down why we need to make this unique in the first place - const uniquePatterns = _.uniq( - _.flatMapDeep(allPatterns, pattern => { - return pattern; - }) + // todo track down why we need to make this unique in the first place + const uniquePatterns = uniqueAllPatterns( + allPatterns, + patternlab ); - //add the defaultPattern if we found one + // add the defaultPattern if we found one if (patternlab.defaultPattern) { uniquePatterns.push(patternlab.defaultPattern); addToPatternPaths(patternlab, patternlab.defaultPattern); } - //build the main styleguide page + // build the main styleguide page return render( - Pattern.createEmpty({ - extendedTemplate: uikit.viewAll, - }), + Pattern.createEmpty( + { + extendedTemplate: uikit.viewAll, + }, + patternlab + ), { partials: uniquePatterns, }, @@ -834,7 +850,7 @@ const ui_builder = function() { logger.info('Built Pattern Lab front end'); - //move the index file from its asset location into public root + // move the index file from its asset location into public root let patternlabSiteHtml; try { patternlabSiteHtml = fs.readFileSync( @@ -864,7 +880,7 @@ const ui_builder = function() { patternlabSiteHtml ); - //write out patternlab.data object to be read by the client + // write out patternlab.data object to be read by the client exportData(patternlab); resolve(); }) @@ -885,31 +901,12 @@ const ui_builder = function() { } return { - buildFrontend: function(patternlab) { - return buildFrontend(patternlab); - }, - isPatternExcluded: function(pattern, patternlab, uikit) { - return isPatternExcluded(pattern, patternlab, uikit); - }, - groupPatterns: function(patternlab, uikit) { - return groupPatterns(patternlab, uikit); - }, - resetUIBuilderState: function(patternlab) { - resetUIBuilderState(patternlab); - }, - buildViewAllPages: function( - mainPageHeadHtml, - patternlab, - styleguidePatterns, - uikit - ) { - return buildViewAllPages( - mainPageHeadHtml, - patternlab, - styleguidePatterns, - uikit - ); - }, + buildFrontend: buildFrontend, + isPatternExcluded: isPatternExcluded, + groupPatterns: groupPatterns, + resetUIBuilderState: resetUIBuilderState, + uniqueAllPatterns: uniqueAllPatterns, + buildViewAllPages: buildViewAllPages, }; }; diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js index 910c02d89..b5835f417 100644 --- a/packages/core/test/object_factory_tests.js +++ b/packages/core/test/object_factory_tests.js @@ -79,8 +79,8 @@ tap.test( path.sep + 'colors.mustache' ); - test.equals(p.name, '00-atoms-00-global'); - test.equals(p.subdir, '00-atoms' + path.sep + '00-global'); + test.equals(p.name, '00-atoms-00-global-00-colors'); + test.equals(p.subdir, path.join('00-atoms', '00-global', '00-colors')); test.equals(p.fileName, 'colors'); test.equals(p.fileExtension, '.mustache'); test.equals(p.jsonFileData.d, 123); @@ -88,10 +88,12 @@ tap.test( test.equals(p.patternName, 'Colors'); test.equals( p.getPatternLink(pl), - '00-atoms-00-global' + path.sep + '00-atoms-00-global.rendered.html' + '00-atoms-00-global-00-colors' + + path.sep + + '00-atoms-00-global-00-colors.rendered.html' ); test.equals(p.patternGroup, 'atoms'); - test.equals(p.patternSubGroup, 'global'); //because of p.info.hasDir + test.equals(p.patternSubGroup, 'global'); test.equals(p.flatPatternPath, '00-atoms-00-global'); test.equals(p.patternPartial, 'atoms-colors'); test.equals(p.template, ''); @@ -106,14 +108,17 @@ tap.test( ); tap.test('test Pattern name for variants correctly initialzed', function(test) { - var p1 = new Pattern('00-atoms/00-global/colors~variant.mustache', { - d: 123, - }); - var p2 = new Pattern('00-atoms/00-global/colors~variant-minus.json', { + var p1 = new Pattern('00-atoms/00-global/00-colors/colors~variant.mustache', { d: 123, }); - test.equals(p1.name, '00-atoms-00-global-colors-variant'); - test.equals(p2.name, '00-atoms-00-global-colors-variant-minus'); + var p2 = new Pattern( + '00-atoms/00-global/00-colors/colors~variant-minus.json', + { + d: 123, + } + ); + test.equals(p1.name, '00-atoms-00-global-00-colors-variant'); + test.equals(p2.name, '00-atoms-00-global-00-colors-variant-minus'); test.end(); }); @@ -177,17 +182,17 @@ tap.test('test Pattern get dir level no separated pattern directory', function( ) { var p = new Pattern('00-atoms/00-global/00-colors-alt.mustache', { d: 123 }); console.log(p); - test.equals(p.getDirLevel(0, { hasDir: false, dirLevel: 2 }), '00-atoms'); - test.equals(p.getDirLevel(1, { hasDir: false, dirLevel: 2 }), '00-global'); - test.equals(p.getDirLevel(3, { hasDir: false, dirLevel: 2 }), ''); + test.equals(p.getDirLevel(0, { patternHasOwnDir: false }), '00-atoms'); + test.equals(p.getDirLevel(1, { patternHasOwnDir: false }), '00-global'); + test.equals(p.getDirLevel(2, { patternHasOwnDir: false }), ''); // There is no third level var p = new Pattern('00-atoms/00-colors-alt.mustache', { d: 123 }); - test.equals(p.getDirLevel(0, { hasDir: false, dirLevel: 1 }), '00-atoms'); - test.equals(p.getDirLevel(1, { hasDir: false, dirLevel: 1 }), '00-atoms'); - test.equals(p.getDirLevel(3, { hasDir: false, dirLevel: 1 }), ''); + test.equals(p.getDirLevel(0, { patternHasOwnDir: false }), '00-atoms'); + test.equals(p.getDirLevel(1, { patternHasOwnDir: false }), ''); // There is no second level + test.equals(p.getDirLevel(2, { patternHasOwnDir: false }), ''); // There is no third level var p = new Pattern('00-colors-alt.mustache', { d: 123 }); - test.equals(p.getDirLevel(0, { hasDir: false, dirLevel: 0 }), ''); - test.equals(p.getDirLevel(1, { hasDir: false, dirLevel: 0 }), ''); - test.equals(p.getDirLevel(3, { hasDir: false, dirLevel: 0 }), ''); + test.equals(p.getDirLevel(0, { patternHasOwnDir: false }), 'root'); // No first level means root + test.equals(p.getDirLevel(1, { patternHasOwnDir: false }), ''); // There is no second level + test.equals(p.getDirLevel(2, { patternHasOwnDir: false }), ''); // There is no third leveL test.end(); }); @@ -198,32 +203,79 @@ tap.test( '00-atoms/00-global/00-colors-alt/colors-alt.mustache', { d: 123 } ); - test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 3 }), '00-atoms'); - test.equals(p.getDirLevel(1, { hasDir: true, dirLevel: 3 }), '00-global'); - test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 3 }), ''); + test.equals(p.getDirLevel(0, { patternHasOwnDir: true }), '00-atoms'); + test.equals(p.getDirLevel(1, { patternHasOwnDir: true }), '00-global'); + test.equals(p.getDirLevel(2, { patternHasOwnDir: true }), ''); // There is no third level + var p = new Pattern('00-atoms/00-colors-alt/colors-alt.mustache', { d: 123, }); - test.equals(p.getDirLevel(0, { hasDir: true, dirLevel: 2 }), '00-atoms'); - test.equals( - p.getDirLevel(1, { hasDir: true, dirLevel: 2 }), - '00-colors-alt' - ); - test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 2 }), ''); + test.equals(p.getDirLevel(0, { patternHasOwnDir: true }), '00-atoms'); + test.equals(p.getDirLevel(1, { patternHasOwnDir: true }), ''); // There is no second level + test.equals(p.getDirLevel(2, { patternHasOwnDir: true }), ''); // There is no third level + var p = new Pattern('00-colors-alt/colors-alt.mustache', { d: 123 }); - test.equals( - p.getDirLevel(0, { hasDir: true, dirLevel: 1 }), - '00-colors-alt' - ); - test.equals( - p.getDirLevel(1, { hasDir: true, dirLevel: 1 }), - '00-colors-alt' + test.equals(p.getDirLevel(0, { patternHasOwnDir: true }), 'root'); // No first level means root + test.equals(p.getDirLevel(1, { patternHasOwnDir: true }), ''); // There is no second level + test.equals(p.getDirLevel(2, { patternHasOwnDir: true }), ''); // There is no third leveL + + var p = new Pattern( + '00-atoms/00-global/00-colors-alt/colors-alt~variant.mustache', + { d: 123 } ); - test.equals(p.getDirLevel(3, { hasDir: true, dirLevel: 1 }), ''); + test.equals(p.name, '00-atoms-00-global-00-colors-alt-variant'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + test.equals(p.patternBaseName, 'colors-alt-variant'); + test.end(); } ); +tap.test('test Patterns that are nested deeper without own directory', function( + test +) { + var p = new Pattern( + '00-atoms/00-global/00-random-folder/00-colors-alt.mustache', + { + d: 123, + } + ); + test.equals(p.name, '00-atoms-00-global-00-colors-alt'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + + var p = new Pattern( + '00-atoms/00-global/00-random-folder/00-another-folder/00-colors-alt.mustache', + { + d: 123, + } + ); + test.equals(p.name, '00-atoms-00-global-00-colors-alt'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + + var p = new Pattern( + '00-atoms/00-global/00-random-folder/00-another-folder/00-some-folder/00-colors-alt.mustache', + { d: 123 } + ); + test.equals(p.name, '00-atoms-00-global-00-colors-alt'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + + var p = new Pattern( + '00-atoms/00-global/00-random-folder/00-another-folder/00-colors-alt/colors-alt.mustache', + { d: 123 } + ); + test.equals(p.name, '00-atoms-00-global-00-colors-alt'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + + var p = new Pattern( + '00-atoms/00-global/00-random-folder/00-another-folder/00-some-folder/00-colors-alt~variant.mustache', + { d: 123 } + ); + test.equals(p.name, '00-atoms-00-global-00-colors-alt-variant'); + test.equals(p.flatPatternPath, '00-atoms-00-global'); + test.equals(p.patternBaseName, 'colors-alt-variant'); + test.end(); +}); + tap.test('The forms of Pattern.getPatternLink() work as expected', function( test ) { diff --git a/packages/core/test/ui_builder_tests.js b/packages/core/test/ui_builder_tests.js index 607d9fd95..3ac42f2f1 100644 --- a/packages/core/test/ui_builder_tests.js +++ b/packages/core/test/ui_builder_tests.js @@ -183,6 +183,7 @@ tap.test('groupPatterns - creates pattern groups correctly', function(test) { }); patternlab.patterns.push( + new Pattern('foobar.mustache'), new Pattern('00-test/bar.mustache'), new Pattern('00-test/foo.mustache'), new Pattern('patternType1/patternSubType1/blue.mustache'), @@ -222,13 +223,19 @@ tap.test('groupPatterns - creates pattern groups correctly', function(test) { 'patternType1-white' ); + // Flat patterns test.equals( patternlab.patternTypes[0].patternItems[0].patternPartial, + 'root-foobar', + 'flat pattern foobar on root' + ); + test.equals( + patternlab.patternTypes[1].patternItems[0].patternPartial, 'test-bar', 'first pattern item should be test-bar' ); test.equals( - patternlab.patternTypes[0].patternItems[1].patternPartial, + patternlab.patternTypes[1].patternItems[1].patternPartial, 'test-foo', 'second pattern item should be test-foo' ); @@ -248,13 +255,15 @@ tap.test('groupPatterns - orders patterns when provided from md', function( subtypePatterns: {}, }); + // Should be sorted by order and secondly by name patternlab.patterns.push( - new Pattern('patternType1/patternSubType1/blue.mustache'), + new Pattern('patternType1/patternSubType1/yellow.mustache'), new Pattern('patternType1/patternSubType1/red.mustache'), - new Pattern('patternType1/patternSubType1/yellow.mustache') + new Pattern('patternType1/patternSubType1/blue.mustache') ); ui.resetUIBuilderState(patternlab); + // Set order of red to 1 to sort it after the others patternlab.patterns[1].order = 1; //act @@ -270,10 +279,10 @@ tap.test('groupPatterns - orders patterns when provided from md', function( ]); var items = patternSubType.patternSubtypeItems; - //zero is viewall - test.equals(items[1].patternPartial, 'patternType1-red'); - test.equals(items[2].patternPartial, 'patternType1-blue'); - test.equals(items[3].patternPartial, 'patternType1-yellow'); + // Viewall should come last since it shows all patterns that are above + test.equals(items[0].patternPartial, 'patternType1-blue'); + test.equals(items[1].patternPartial, 'patternType1-yellow'); + test.equals(items[2].patternPartial, 'patternType1-red'); test.end(); }); @@ -310,10 +319,10 @@ tap.test( ]); var items = patternSubType.patternSubtypeItems; - //zero is viewall - test.equals(items[1].patternPartial, 'patternType1-blue'); - test.equals(items[2].patternPartial, 'patternType1-red'); - test.equals(items[3].patternPartial, 'patternType1-yellow'); + // Viewall should come last since it shows all patterns that are above + test.equals(items[0].patternPartial, 'patternType1-blue'); + test.equals(items[1].patternPartial, 'patternType1-red'); + test.equals(items[2].patternPartial, 'patternType1-yellow'); test.end(); } @@ -353,14 +362,14 @@ tap.test( ]); var items = patternSubType.patternSubtypeItems; - //zero is viewall + // Viewall should come last since it shows all patterns that are above test.equals( - items[0].patternPartial, + items[3].patternPartial, 'viewall-patternType1-patternSubType1' ); - test.equals(items[1].patternPartial, 'patternType1-blue'); - test.equals(items[2].patternPartial, 'patternType1-yellow'); - test.equals(items[3].patternPartial, 'patternType1-red'); + test.equals(items[0].patternPartial, 'patternType1-blue'); + test.equals(items[1].patternPartial, 'patternType1-yellow'); + test.equals(items[2].patternPartial, 'patternType1-red'); test.end(); } @@ -546,40 +555,42 @@ tap.test( const styleguidePatterns = ui.groupPatterns(patternlab, uikit); //act - ui - .buildViewAllPages( - mainPageHeadHtml, - patternlab, - styleguidePatterns, - uikit - ) - .then(allPatterns => { - //assert - //this was a nuanced one. buildViewAllPages() had return false; statements - //within _.forOwn(...) loops, causing premature termination of the entire loop - //when what was intended was a continue - //we expect 8 here because: - // - foo.mustache is flat and therefore does not have a viewall page - // - the colors.mustache files make 6 - // - patternSubType1 and patternSubType2 make 8 - //while most of that heavy lifting occurs inside groupPatterns and not buildViewAllPages, - //it's important to ensure that this method does not get prematurely terminated - //we choose to do that by checking it's return number of patterns - - //todo: this workaround matches the code at the moment - const uniquePatterns = _.uniq( - _.flatMapDeep(allPatterns, pattern => { - return pattern; - }) - ); - - test.equals( - uniquePatterns.length, - 8, - '2 viewall pages should be added' - ); - - test.end(); - }); + ui.buildViewAllPages( + mainPageHeadHtml, + patternlab, + styleguidePatterns, + uikit + ).then(allPatterns => { + // assert + // this was a nuanced one. buildViewAllPages() had return false; statements + // within _.forOwn(...) loops, causing premature termination of the entire loop + // when what was intended was a continue + // we expect 8 here because: + // - foo.mustache is flat and therefore does not have a viewall page + // - the colors.mustache files make 6 + // - patternSubType1 and patternSubType2 make 8 + // while most of that heavy lifting occurs inside groupPatterns and not buildViewAllPages, + // it's important to ensure that this method does not get prematurely terminated + // we choose to do that by checking it's return number of patterns + + const uniquePatterns = ui.uniqueAllPatterns(allPatterns, patternlab); + + /** + * - viewall-test-all + * -- test-foo + * - view-patternType1-all + * -- viewall-patternType1-patternSubType1 + * --- blue + * --- red + * --- yellow + * -- viewall-patternType1-patternSubType2 + * --- black + * --- grey + * --- white + */ + test.equals(uniquePatterns.length, 11, '4 viewall pages should be added'); + + test.end(); + }); } ); diff --git a/packages/edition-node/patternlab-config.json b/packages/edition-node/patternlab-config.json index e5cef6811..2db440279 100644 --- a/packages/edition-node/patternlab-config.json +++ b/packages/edition-node/patternlab-config.json @@ -75,6 +75,10 @@ "patternExportPatternPartials": [], "patternExportPreserveDirectoryStructure": true, "patternExportRaw": false, + "patternTranslations": { + "view-all": "View all {groupName}", + "root-name": "Root" + }, "serverOptions": { "wait": 1000 }, diff --git a/packages/engine-mustache/lib/engine_mustache.js b/packages/engine-mustache/lib/engine_mustache.js index dc0838cfd..59aa04501 100644 --- a/packages/engine-mustache/lib/engine_mustache.js +++ b/packages/engine-mustache/lib/engine_mustache.js @@ -29,7 +29,7 @@ const utilMustache = require('./util_mustache'); // it does, so we're cool, right? let patternLabConfig = {}; -var engine_mustache = { +const engine_mustache = { engine: Mustache, engineName: 'mustache', engineFileExtension: '.mustache', @@ -69,7 +69,7 @@ var engine_mustache = { * @returns {array|null} An array if a match is found, null if not. */ patternMatcher: function patternMatcher(pattern, regex) { - var matches; + let matches; if (typeof pattern === 'string') { matches = pattern.match(regex); } else if ( @@ -110,43 +110,35 @@ var engine_mustache = { // find and return any {{> template-name }} within pattern findPartials: function findPartials(pattern) { - var matches = this.patternMatcher(pattern, this.findPartialsRE); - return matches; + return this.patternMatcher(pattern, this.findPartialsRE); }, findPartialsWithStyleModifiers: function(pattern) { - var matches = this.patternMatcher( - pattern, - this.findPartialsWithStyleModifiersRE - ); - return matches; + return this.patternMatcher(pattern, this.findPartialsWithStyleModifiersRE); }, // returns any patterns that match {{> value(foo:"bar") }} or {{> // value:mod(foo:"bar") }} within the pattern findPartialsWithPatternParameters: function(pattern) { - var matches = this.patternMatcher( + return this.patternMatcher( pattern, this.findPartialsWithPatternParametersRE ); - return matches; }, findListItems: function(pattern) { - var matches = this.patternMatcher(pattern, this.findListItemsRE); - return matches; + return this.patternMatcher(pattern, this.findListItemsRE); }, // given a pattern, and a partial string, tease out the "pattern key" and // return it. findPartial_new: function(partialString) { - var partial = partialString.replace(this.findPartialRE, '$1'); - return partial; + return partialString.replace(this.findPartialRE, '$1'); }, // GTP: the old implementation works better. We might not need // this.findPartialRE anymore if it works in all cases! findPartial: function(partialString) { //strip out the template cruft - var foundPatternPartial = partialString + let foundPatternPartial = partialString .replace('{{> ', '') .replace(' }}', '') .replace('{{>', '') diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss index abe9d6142..fbca575bb 100644 --- a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss +++ b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss @@ -10,11 +10,15 @@ */ .pl-c-category { margin-top: 6rem; - font: $pl-font !important; + font-family: $pl-font !important; &:first-of-type { margin-top: 2rem; } + + & + & { + margin-top: 2rem; + } } /** @@ -25,6 +29,10 @@ color: $pl-color-gray-87 !important; margin: 0 0 0.2rem; text-transform: capitalize; + + &:hover { + color: $pl-color-gray-70 !important; + } } /** @@ -32,6 +40,7 @@ */ .pl-c-category__title-link { transition: color $pl-animate-quick ease-out; + color: inherit; } /** diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index af3d0bf26..15e89203d 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -415,7 +415,7 @@ class Nav extends BaseComponent { return ( {patternSubtype.patternSubtypeItems} From c94531b8fbaa80dc44a2a87582a53869a35d4e4e Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Mon, 13 Apr 2020 02:51:07 +0200 Subject: [PATCH 004/330] Ability for viewall page links and updated test to realworld --- packages/core/src/lib/parseLink.js | 71 +++++++---- .../test/files/_patterns/00-test/nav.json | 32 +++-- packages/core/test/parseAllLinks_tests.js | 118 ++++++++++++++---- 3 files changed, 168 insertions(+), 53 deletions(-) diff --git a/packages/core/src/lib/parseLink.js b/packages/core/src/lib/parseLink.js index d3d0c455e..368ce4cc8 100644 --- a/packages/core/src/lib/parseLink.js +++ b/packages/core/src/lib/parseLink.js @@ -20,37 +20,64 @@ module.exports = function(patternlab, obj, key) { const linkMatches = dataObjAsString.match(linkRE); if (linkMatches) { - for (let i = 0; i < linkMatches.length; i++) { - const dataLink = linkMatches[i]; + linkMatches.forEach(dataLink => { if (dataLink && dataLink.split('.').length >= 2) { //get the partial the link refers to - const linkPatternPartial = dataLink - .split('.')[1] - .replace('"', '') - .replace("'", ''); - const pattern = getPartial(linkPatternPartial, patternlab); - if (pattern !== undefined) { - //get the full built link and replace it - let fullLink = patternlab.data.link[linkPatternPartial]; - if (fullLink) { - fullLink = path.normalize(fullLink).replace(/\\/g, '/'); + const linkPatternPartial = dataLink.split('.')[1].replace(/'|"/g, ''); + const rawLink = `link.${linkPatternPartial}`; + let replacement = null; - logger.debug( - `expanded data link from ${dataLink} to ${fullLink} inside ${key}` - ); + if (linkPatternPartial.match(/viewall\-.+\-all/)) { + // Reverse engineer viewall-group-all link (if there is a pattern with that + // group there will be a view all page for that group) + const partial = linkPatternPartial + .replace('viewall-', '') + .replace('-all', ''); + const pattern = patternlab.patterns.find( + p => p.patternGroup === partial + ); - //also make sure our global replace didn't mess up a protocol - fullLink = fullLink.replace(/:\//g, '://'); - dataObjAsString = dataObjAsString.replace( - 'link.' + linkPatternPartial, - fullLink - ); + if (pattern) { + replacement = `/patterns/${partial}/index.html`; } + } else if (linkPatternPartial.match(/viewall\-.+/)) { + // Reverse engineer viewall-group-subgroup link (if there is a pattern with that + // group and subgroup there will be a view all page for that group) + const partial = linkPatternPartial.replace('viewall-', ''); + const pattern = patternlab.patterns.find( + p => `${p.patternGroup}-${p.patternSubGroup}` === partial + ); + + if (pattern) { + replacement = `/patterns/${pattern.flatPatternPath}/index.html`; + } + } else { + // Just search for the pattern partial + const pattern = getPartial(linkPatternPartial, patternlab); + + if (pattern) { + // get the full built link and replace it + let fullLink = patternlab.data.link[linkPatternPartial]; + if (fullLink) { + fullLink = path.normalize(fullLink).replace(/\\/g, '/'); + + logger.debug( + `expanded data link from ${dataLink} to ${fullLink} inside ${key}` + ); + + // also make sure our global replace didn't mess up a protocol + replacement = fullLink.replace(/:\//g, '://'); + } + } + } + + if (replacement) { + dataObjAsString = dataObjAsString.replace(rawLink, replacement); } else { logger.warning(`pattern not found for ${dataLink} inside ${key}`); } } - } + }); } let dataObj; diff --git a/packages/core/test/files/_patterns/00-test/nav.json b/packages/core/test/files/_patterns/00-test/nav.json index 32a6c0952..8d47a2491 100644 --- a/packages/core/test/files/_patterns/00-test/nav.json +++ b/packages/core/test/files/_patterns/00-test/nav.json @@ -1,11 +1,29 @@ { - "brad" : { - "url" : "link.twitter-brad" + "brad": { + "url": "link.twitter-brad" }, - "dave" : { - "url" : "link.twitter-dave" + "dave": { + "url": "link.twitter-dave" }, - "brian" : { - "url" : "link.twitter-brian" + "brian": { + "url": "link.twitter-brian" + }, + "someone": { + "url": "link.twitter-someone" + }, + "someone2": { + "url": "link.facebook-someone2" + }, + "viewall-twitter": { + "url": "link.viewall-twitter-all" + }, + "viewall-twitter-people": { + "url": "link.viewall-twitter-people" + }, + "viewall-facebook": { + "url": "link.viewall-facebook-all" + }, + "viewall-facebook-people": { + "url": "link.viewall-facebook-people" } -} +} \ No newline at end of file diff --git a/packages/core/test/parseAllLinks_tests.js b/packages/core/test/parseAllLinks_tests.js index 271b3ee5b..1d52c4276 100644 --- a/packages/core/test/parseAllLinks_tests.js +++ b/packages/core/test/parseAllLinks_tests.js @@ -22,15 +22,21 @@ tap.test( const patternlab = util.fakePatternLab(patterns_dir); patternlab.graph = PatternGraph.empty(); - patternlab.patterns = [ - Pattern.createEmpty({ patternPartial: 'twitter-brad' }, patternlab), - Pattern.createEmpty({ patternPartial: 'twitter-dave' }, patternlab), - Pattern.createEmpty({ patternPartial: 'twitter-brian' }, patternlab), - ]; - patternlab.data.link = {}; + addPattern(new Pattern('twitter/brad.hbs', {}, patternlab), patternlab); + addPattern(new Pattern('twitter/dave.hbs', {}, patternlab), patternlab); + addPattern(new Pattern('twitter/brian.hbs', {}, patternlab), patternlab); + addPattern( + new Pattern('twitter/people/someone.hbs', {}, patternlab), + patternlab + ); + // Test with pattern prefix + addPattern( + new Pattern('01-facebook/02-people/03-someone2.hbs', {}, patternlab), + patternlab + ); // copies essential logic from loadPattern - const navPattern = new Pattern('00-test/nav.mustache'); + const navPattern = new Pattern('00-test/nav.mustache', {}, patternlab); const patternData = dataLoader.loadDataFromFile( path.resolve( __dirname, @@ -43,21 +49,15 @@ tap.test( navPattern.jsonFileData = patternData; addPattern(navPattern, patternlab); - //for the sake of the test, also imagining I have the following pages... - patternlab.data.link['twitter-brad'] = 'https://twitter.com/brad_frost'; - patternlab.data.link['twitter-dave'] = 'https://twitter.com/dmolsen'; - patternlab.data.link['twitter-brian'] = 'https://twitter.com/bmuenzenmeyer'; - patternlab.data.brad = { url: 'link.twitter-brad' }; patternlab.data.dave = { url: 'link.twitter-dave' }; patternlab.data.brian = { url: 'link.twitter-brian' }; + patternlab.data.someone = { url: 'link.twitter-someone' }; + patternlab.data.someone2 = { url: 'link.facebook-someone2' }; - let pattern; - for (let i = 0; i < patternlab.patterns.length; i++) { - if (patternlab.patterns[i].patternPartial === 'test-nav') { - pattern = patternlab.patterns[i]; - } - } + let pattern = patternlab.patterns.find( + p => p.patternPartial === 'test-nav' + ); //assert before test.equals( @@ -75,6 +75,36 @@ tap.test( 'link.twitter-brian', 'brian pattern data should be found' ); + test.equals( + pattern.jsonFileData.someone.url, + 'link.twitter-someone', + 'brian pattern data should be found' + ); + test.equals( + pattern.jsonFileData.someone2.url, + 'link.facebook-someone2', + 'brian pattern data should be found' + ); + test.equals( + pattern.jsonFileData['viewall-twitter'].url, + 'link.viewall-twitter-all', + 'view all twitter link should be found' + ); + test.equals( + pattern.jsonFileData['viewall-twitter-people'].url, + 'link.viewall-twitter-people', + 'view all twitter people link should be found' + ); + test.equals( + pattern.jsonFileData['viewall-facebook'].url, + 'link.viewall-facebook-all', + 'view all facebook link should be found' + ); + test.equals( + pattern.jsonFileData['viewall-facebook-people'].url, + 'link.viewall-facebook-people', + 'view all facebook people link should be found' + ); //act parseAllLinks(patternlab); @@ -82,35 +112,75 @@ tap.test( //assert after test.equals( pattern.jsonFileData.brad.url, - 'https://twitter.com/brad_frost', + '/patterns/twitter-brad/twitter-brad.rendered.html', 'brad pattern data should be replaced' ); test.equals( pattern.jsonFileData.dave.url, - 'https://twitter.com/dmolsen', + '/patterns/twitter-dave/twitter-dave.rendered.html', 'dave pattern data should be replaced' ); test.equals( pattern.jsonFileData.brian.url, - 'https://twitter.com/bmuenzenmeyer', + '/patterns/twitter-brian/twitter-brian.rendered.html', 'brian pattern data should be replaced' ); + test.equals( + pattern.jsonFileData.someone.url, + '/patterns/twitter-people-someone/twitter-people-someone.rendered.html', + 'twitter people someone pattern data should be replaced' + ); + test.equals( + pattern.jsonFileData.someone2.url, + '/patterns/01-facebook-02-people-03-someone2/01-facebook-02-people-03-someone2.rendered.html', + 'facebook people someone2 pattern data should be replaced with prefix pattern' + ); + test.equals( + pattern.jsonFileData['viewall-twitter'].url, + '/patterns/twitter/index.html', + 'view all twitter link should be replaced' + ); + test.equals( + pattern.jsonFileData['viewall-twitter-people'].url, + '/patterns/twitter-people/index.html', + 'view all twitter people link should be replaced' + ); + test.equals( + pattern.jsonFileData['viewall-facebook'].url, + '/patterns/facebook/index.html', + 'view all facebook link should be replaced' + ); + test.equals( + pattern.jsonFileData['viewall-facebook-people'].url, + '/patterns/01-facebook-02-people/index.html', + 'view all facebook people link should be replaced' + ); test.equals( patternlab.data.brad.url, - 'https://twitter.com/brad_frost', + '/patterns/twitter-brad/twitter-brad.rendered.html', 'global brad data should be replaced' ); test.equals( patternlab.data.dave.url, - 'https://twitter.com/dmolsen', + '/patterns/twitter-dave/twitter-dave.rendered.html', 'global dave data should be replaced' ); test.equals( patternlab.data.brian.url, - 'https://twitter.com/bmuenzenmeyer', + '/patterns/twitter-brian/twitter-brian.rendered.html', 'global brian data should be replaced' ); + test.equals( + patternlab.data.someone.url, + '/patterns/twitter-people-someone/twitter-people-someone.rendered.html', + 'twitter people someone pattern data should be replaced' + ); + test.equals( + patternlab.data.someone2.url, + '/patterns/01-facebook-02-people-03-someone2/01-facebook-02-people-03-someone2.rendered.html', + 'facebook people someone2 pattern data should be replaced with prefix pattern' + ); test.end(); } ); From e39a881dd828a8ebb142b225e29d939a4d1ad3cc Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Mon, 13 Apr 2020 17:03:38 +0200 Subject: [PATCH 005/330] Fix "Open In New Tab" incorrect link --- .../src/scripts/lit-components/pl-viewport/pl-viewport.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js index 99a456810..8fd02933a 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js @@ -491,6 +491,10 @@ class IFrame extends BaseLitComponent { this.sanitizePatternName(event.data.patternpartial) || this.getPatternParam(); + store.dispatch( + updateCurrentUrl(urlHandler.getFileName(currentPattern)) + ); + document.title = 'Pattern Lab - ' + currentPattern; const addressReplacement = From e72b8b4d9e72a934ac35af62bdeb646c6edcd6c0 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Fri, 17 Apr 2020 20:21:07 +0200 Subject: [PATCH 006/330] #1143: Add func. to specify if pattern has own dir --- packages/core/src/lib/markdown_parser.js | 5 +- packages/core/src/lib/object_factory.js | 81 +++++++++++++++------- packages/core/src/lib/readDocumentation.js | 5 ++ 3 files changed, 64 insertions(+), 27 deletions(-) diff --git a/packages/core/src/lib/markdown_parser.js b/packages/core/src/lib/markdown_parser.js index c940a5f67..224d8012a 100644 --- a/packages/core/src/lib/markdown_parser.js +++ b/packages/core/src/lib/markdown_parser.js @@ -13,8 +13,9 @@ const markdown_parser = function() { let returnObject = {}; try { - //for each block process the yaml frontmatter and markdown - const frontmatterRE = /---\r?\n{1}([\s\S]*)---\r?\n{1}([\s\S]*)+/gm; + // for each block process the yaml frontmatter and markdown + // even if the pattern only has pattern data without further documentation + const frontmatterRE = /---\r?\n{1}([\s\S]*)---([\s\S]*)+/gm; const chunks = frontmatterRE.exec(block); if (chunks) { diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 90c30112d..3f004828c 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -16,22 +16,23 @@ const prefixMatcher = /^_?(\d+-)?/; * to get more details about the behavior of the folder structure * https://github.com/pattern-lab/patternlab-node/pull/992 * https://github.com/pattern-lab/patternlab-node/pull/1016 + * https://github.com/pattern-lab/patternlab-node/pull/1143 * - * @constructor + * @param {String} relPath relative directory + * @param {Object} jsonFileData The JSON used to render values in the pattern. + * @param {Patternlab} patternlab The actual patternlab instance + * @param {Boolean} isUnsubRun specifies if the pattern needs to be unsubbed from its folder */ -const Pattern = function(relPath, data, patternlab) { +const Pattern = function(relPath, jsonFileData, patternlab, isUnsubRun) { this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' /** * We expect relPath to be the path of the pattern template, relative to the * root of the pattern tree. Parse out the path parts and save the useful ones. - * @param {relPath} relative directory - * @param {data} The JSON used to render values in the pattern. - * @param {patternlab} rendered html files for the pattern */ const pathObj = path.parse(this.relPath); - const info = this.getPatternInfo(pathObj, patternlab); + const info = this.getPatternInfo(pathObj, patternlab, isUnsubRun); this.fileName = pathObj.name; // '00-colors' this.subdir = pathObj.dir; // '00-atoms/00-global' @@ -41,8 +42,8 @@ const Pattern = function(relPath, data, patternlab) { if (info.patternHasOwnDir) { // Since there is still the requirement of having the numbers provided for sorting // this will be required to keep the folder prefix and the variant name - // /00-atoms/00-global/00-colors/colors~varian.hbs - // -> 00-atoms-00-global-00-colors + // /00-atoms/00-global/00-colors/colors~variant.hbs + // -> 00-atoms-00-global-00-colors-variant this.name = `${info.shortNotation}-${path.parse(pathObj.dir).base}${ this.fileName.indexOf('~') !== -1 ? '-' + this.fileName.split('~')[1] : '' }`; @@ -52,7 +53,7 @@ const Pattern = function(relPath, data, patternlab) { } // the JSON used to render values in the pattern - this.jsonFileData = data || {}; + this.jsonFileData = jsonFileData || {}; // strip leading "00-" from the file name and flip tildes to dashes this.patternBaseName = this.fileName @@ -188,8 +189,10 @@ Pattern.prototype = { return this.name + path.sep + this.name + suffix + '.html'; }, - // the finders all delegate to the PatternEngine, which also encapsulates all - // appropriate regexes + /** + * The finders all delegate to the PatternEngine, which also + * encapsulates all appropriate regexes + */ findPartials: function() { return this.engine.findPartials(this); }, @@ -210,9 +213,15 @@ Pattern.prototype = { return this.engine.findPartial(partialString); }, - getDirLevel: function(level, pathInfo) { + /** + * Get a directory on a specific level of the pattern path + * + * @param {Number} level Level of folder to get + * @param {Object} pInfo general information about the pattern + */ + getDirLevel: function(level, pInfo) { const items = this.subdir.split(path.sep); - pathInfo.patternHasOwnDir && items.pop(); + pInfo && pInfo.patternHasOwnDir && items.pop(); if (items[level]) { return items[level]; @@ -221,16 +230,37 @@ Pattern.prototype = { } else { // Im Not quite shure about that but its better than empty node // TODO: verify - return pathInfo.patternlab && - pathInfo.patternlab.config.patternTranslations && - pathInfo.patternlab.config.patternTranslations['root-name'] - ? _.kebabCase( - pathInfo.patternlab.config.patternTranslations['root-name'] - ) + return pInfo.patternlab && + pInfo.patternlab.config.patternTranslations && + pInfo.patternlab.config.patternTranslations['root-name'] + ? _.kebabCase(pInfo.patternlab.config.patternTranslations['root-name']) : 'root'; } }, + /** + * Reset the information that the pattern has it's own directory, + * so that this pattern will not be handled as flat pattern if it + * is located on a top level folder. + * + * @param {Patternlab} patternlab Current patternlab instance + */ + resetSubbing: function(patternlab) { + const p = new Pattern(this.relPath, this.jsonFileData, patternlab, true); + // Only reset the specific fields, not everything + Object.assign(this, { + patternLink: p.patternLink, + patternGroup: p.patternGroup, + patternType: p.patternType, + patternSubGroup: p.patternSubGroup, + patternSubType: p.patternSubType, + isFlatPattern: p.isFlatPattern, + flatPatternPath: p.flatPatternPath, + patternPartial: p.patternPartial, + verbosePartial: p.verbosePartial, + }); + }, + /** * Info contains information about pattern structure if it is a nested pattern * or if it just a subbed folder structure. Its just used for internal purposes. @@ -238,15 +268,16 @@ Pattern.prototype = { * * @param pathObj path.parse() object containing usefull path information */ - getPatternInfo: (pathObj, patternlab) => { + getPatternInfo: (pathObj, patternlab, isUnsubRun) => { const info = { // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors patternlab: patternlab, - patternHasOwnDir: - path.basename(pathObj.dir).replace(prefixMatcher, '') === - pathObj.name.replace(prefixMatcher, '') || - path.basename(pathObj.dir).replace(prefixMatcher, '') === - pathObj.name.split('~')[0].replace(prefixMatcher, ''), + patternHasOwnDir: !isUnsubRun + ? path.basename(pathObj.dir).replace(prefixMatcher, '') === + pathObj.name.replace(prefixMatcher, '') || + path.basename(pathObj.dir).replace(prefixMatcher, '') === + pathObj.name.split('~')[0].replace(prefixMatcher, '') + : false, }; info.dir = info.patternHasOwnDir ? pathObj.dir.split(path.sep).pop() : ''; diff --git a/packages/core/src/lib/readDocumentation.js b/packages/core/src/lib/readDocumentation.js index 2670bb307..bfe35b983 100644 --- a/packages/core/src/lib/readDocumentation.js +++ b/packages/core/src/lib/readDocumentation.js @@ -54,6 +54,11 @@ module.exports = function(pattern, patternlab) { if (markdownObject.links) { pattern.links = markdownObject.links; } + + if (markdownObject.hasOwnProperty('subbed') && !markdownObject.subbed) { + // Reset to pattern without own pattern-directory + pattern.resetSubbing(patternlab); + } } else { logger.warning(`error processing markdown for ${pattern.patternPartial}`); } From 5003a6a8b3bbe19cc278849580b25c73e86e0ad1 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Fri, 17 Apr 2020 21:28:23 +0200 Subject: [PATCH 007/330] #1143: Add test and fix remaining errors --- packages/core/src/lib/object_factory.js | 14 ++++++++-- packages/core/test/object_factory_tests.js | 32 ++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 3f004828c..f5fe162a2 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -168,9 +168,16 @@ Pattern.prototype = { } }, - // calculated path from the root of the public directory to the generated html - // file for this pattern. - // Should look something like '00-atoms-00-global-00-colors/00-atoms-00-global-00-colors.html' + /** + * calculated path from the root of the public directory to the generated html + * file for this pattern. + * + * Should look something like '00-atoms-00-global-00-colors/00-atoms-00-global-00-colors.html' + * + * @param {Patternlab} patternlab Current patternlab instance + * @param {String} suffixType File suffix + * @param {String} customfileExtension Custom extension + */ getPatternLink: function(patternlab, suffixType, customfileExtension) { // if no suffixType is provided, we default to rendered const suffixConfig = patternlab.config.outputFileSuffixes; @@ -249,6 +256,7 @@ Pattern.prototype = { const p = new Pattern(this.relPath, this.jsonFileData, patternlab, true); // Only reset the specific fields, not everything Object.assign(this, { + name: p.name, patternLink: p.patternLink, patternGroup: p.patternGroup, patternType: p.patternType, diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js index b5835f417..6c7b704df 100644 --- a/packages/core/test/object_factory_tests.js +++ b/packages/core/test/object_factory_tests.js @@ -149,6 +149,38 @@ tap.test('test Pattern with one-directory subdir works as expected', function( test.end(); }); +tap.test('test Pattern with own-directory gets resetted as expected', function( + test +) { + var p = new Pattern('00-atoms/00-button/button.mustache', { d: 123 }, pl); + p.resetSubbing(pl); + + test.equals(p.relPath, path.join('00-atoms', '00-button', 'button.mustache')); + test.equals(p.name, '00-atoms-00-button-button'); + test.equals(p.subdir, path.join('00-atoms', '00-button')); + test.equals(p.fileName, 'button'); + test.equals(p.fileExtension, '.mustache'); + test.equals(p.jsonFileData.d, 123); + test.equals(p.patternBaseName, 'button'); + test.equals(p.patternName, 'Button'); + test.equals( + p.getPatternLink(pl), + path.join( + '00-atoms-00-button-button', + '00-atoms-00-button-button.rendered.html' + ) + ); + test.equals(p.patternGroup, 'atoms'); + test.equals(p.flatPatternPath, '00-atoms-00-button'); + test.equals(p.patternPartial, 'atoms-button'); + test.equals(p.template, ''); + test.equals(p.lineage.length, 0); + test.equals(p.lineageIndex.length, 0); + test.equals(p.lineageR.length, 0); + test.equals(p.lineageRIndex.length, 0); + test.end(); +}); + tap.test( 'test Pattern with no numbers in pattern group works as expected', function(test) { From ffcd61571124b5292b0e982b68df759964b1c026 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Sat, 25 Apr 2020 16:46:23 +0200 Subject: [PATCH 008/330] #1143: Fix translations causing nav bug --- packages/core/patternlab-config.json | 6 ++- packages/core/src/lib/object_factory.js | 4 +- packages/core/src/lib/ui_builder.js | 15 ++++-- packages/edition-node/patternlab-config.json | 6 ++- .../src/scripts/components/pl-nav/pl-nav.js | 53 +++++++++---------- 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/packages/core/patternlab-config.json b/packages/core/patternlab-config.json index 265e98b65..31fcbf748 100644 --- a/packages/core/patternlab-config.json +++ b/packages/core/patternlab-config.json @@ -76,8 +76,10 @@ "patternExportPreserveDirectoryStructure": true, "patternExportRaw": false, "patternTranslations": { - "view-all": "View all {groupName}", - "root-name": "Root" + "ViewAllSubGroup": "View all {sgName}", + "viewAllGroup": "View All", + "viewAllRoot": "All", + "rootName": "Root" }, "serverOptions": { "wait": 1000 diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index f5fe162a2..3df0d3b2c 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -239,8 +239,8 @@ Pattern.prototype = { // TODO: verify return pInfo.patternlab && pInfo.patternlab.config.patternTranslations && - pInfo.patternlab.config.patternTranslations['root-name'] - ? _.kebabCase(pInfo.patternlab.config.patternTranslations['root-name']) + pInfo.patternlab.config.patternTranslations.rootName + ? _.kebabCase(pInfo.patternlab.config.patternTranslations.rootName) : 'root'; } }, diff --git a/packages/core/src/lib/ui_builder.js b/packages/core/src/lib/ui_builder.js index 148a872aa..4d4c371e4 100644 --- a/packages/core/src/lib/ui_builder.js +++ b/packages/core/src/lib/ui_builder.js @@ -262,6 +262,7 @@ const ui_builder = function() { patternState: pattern.patternState, patternPath: pattern.patternLink, name: pattern.name, + isDocPattern: false, order: Number(pattern.order) || 0, // Failsave is someone entered a string }; } @@ -284,11 +285,16 @@ const ui_builder = function() { newSubTypeItem = { patternPartial: 'viewall-' + pattern.patternGroup + '-' + pattern.patternSubGroup, - patternName: 'View All', + patternName: + patternlab.config.patternTranslations && + patternlab.config.patternTranslations.viewAllGroup + ? patternlab.config.patternTranslations.viewAllGroup + : `View all`, patternPath: encodeURI(pattern.flatPatternPath + '/index.html'), patternType: pattern.patternType, patternSubtype: pattern.patternSubtype, name: pattern.flatPatternPath, + isDocPattern: true, order: Number.MAX_SAFE_INTEGER, }; } else { @@ -322,14 +328,15 @@ const ui_builder = function() { patternPartial: `viewall-${pattern.patternGroup}-all`, patternName: patternlab.config.patternTranslations && - patternlab.config.patternTranslations['view-all'] - ? patternlab.config.patternTranslations['view-all'].replace( - '{groupName}', + patternlab.config.patternTranslations.ViewAllSubGroup + ? patternlab.config.patternTranslations.ViewAllSubGroup.replace( + '{sgName}', _.startCase(pattern.patternGroup) ) : `View all ${_.startCase(pattern.patternGroup)}`, patternPath: encodeURI(pattern.patternGroup + '/index.html'), name: pattern.patternGroup, + isDocPattern: true, order: Number.MAX_SAFE_INTEGER, }); } else { diff --git a/packages/edition-node/patternlab-config.json b/packages/edition-node/patternlab-config.json index 2db440279..67472a021 100644 --- a/packages/edition-node/patternlab-config.json +++ b/packages/edition-node/patternlab-config.json @@ -76,8 +76,10 @@ "patternExportPreserveDirectoryStructure": true, "patternExportRaw": false, "patternTranslations": { - "view-all": "View all {groupName}", - "root-name": "Root" + "ViewAllSubGroup": "View all {sgName}", + "viewAllGroup": "View All", + "viewAllRoot": "All", + "rootName": "Root" }, "serverOptions": { "wait": 1000 diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index 15e89203d..744138743 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -14,15 +14,10 @@ const SubSubList = props => { const { children, category, elem } = props; const reorderedChildren = []; - const nonViewAllItems = elem.noViewAll - ? children.filter(item => item.patternName !== 'View All') - : children.filter( - item => - item.patternName !== 'View All' && !item.patternName.includes(' Docs') - ); + const nonViewAllItems = children.filter(item => !item.isDocPattern); const viewAllItems = elem.noViewAll ? [] - : children.filter(item => item.patternName === 'View All'); + : children.filter(item => item.isDocPattern); reorderedChildren.push(...viewAllItems, ...nonViewAllItems); @@ -35,7 +30,7 @@ const SubSubList = props => { href={`patterns/${patternSubtypeItem.patternPath}`} className={`pl-c-nav__link pl-c-nav__link--sublink ${ - patternSubtypeItem.patternName === 'View All' + patternSubtypeItem.isDocPattern ? 'pl-c-nav__link--overview pl-js-link-overview' : 'pl-c-nav__link--subsublink' } @@ -45,7 +40,7 @@ const SubSubList = props => { } data-patternpartial={patternSubtypeItem.patternPartial} > - {patternSubtypeItem.patternName === 'View All' + {patternSubtypeItem.isDocPattern ? `${category}` : patternSubtypeItem.patternName} {patternSubtypeItem.patternState && ( @@ -84,7 +79,7 @@ const SubSubList = props => { href={`patterns/${patternSubtypeItem.patternPath}`} className={`pl-c-nav__link pl-c-nav__link--sublink ${ - patternSubtypeItem.patternName === 'View All' + patternSubtypeItem.isDocPattern ? 'pl-c-nav__link--overview' : 'pl-c-nav__link--subsublink' } @@ -94,7 +89,7 @@ const SubSubList = props => { } data-patternpartial={patternSubtypeItem.patternPartial} > - {patternSubtypeItem.patternName === 'View All' + {patternSubtypeItem.isDocPattern ? `${category} Overview` : patternSubtypeItem.patternName} {patternSubtypeItem.patternState && ( @@ -438,9 +433,7 @@ class Nav extends BaseComponent { data-patternpartial={patternItem.patternPartial} tabindex="0" > - {patternItem.patternName === 'View All' - ? patternItem.patternName + ' ' + item.patternTypeUC - : patternItem.patternName} + {patternItem.patternName} {patternItem.patternState && ( - this.handleClick(e, 'all')} - href="styleguide/html/styleguide.html" - class="pl-c-nav__link pl-c-nav__link--pattern" - data-patternpartial="all" - tabindex="0" - > - All - - - )} + (!window.ishControls.ishControlsHide['views-all'] && + !window.ishControls.ishControlsHide.all)) && + !this.noViewAll && ( +
  • + this.handleClick(e, 'all')} + href="styleguide/html/styleguide.html" + class="pl-c-nav__link pl-c-nav__link--pattern" + data-patternpartial="all" + tabindex="0" + > + {window.config.patternTranslations && + window.config.patternTranslations.viewAllRoot + ? window.config.patternTranslations.viewAllRoot + : 'All'} + +
  • + )} ); } From 2475cacc542ecb33bdaf1e61d38a9d24e8509f46 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Sat, 25 Apr 2020 16:50:37 +0200 Subject: [PATCH 009/330] #1143: Change property to proper name --- packages/core/src/lib/object_factory.js | 6 +++--- packages/core/src/lib/readDocumentation.js | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 3df0d3b2c..36bcb9c6a 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -21,7 +21,7 @@ const prefixMatcher = /^_?(\d+-)?/; * @param {String} relPath relative directory * @param {Object} jsonFileData The JSON used to render values in the pattern. * @param {Patternlab} patternlab The actual patternlab instance - * @param {Boolean} isUnsubRun specifies if the pattern needs to be unsubbed from its folder + * @param {Boolean} isUnsubRun specifies if the pattern needs to be removed from its subfolder */ const Pattern = function(relPath, jsonFileData, patternlab, isUnsubRun) { this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache' @@ -271,14 +271,14 @@ Pattern.prototype = { /** * Info contains information about pattern structure if it is a nested pattern - * or if it just a subbed folder structure. Its just used for internal purposes. + * or if it just a subfolder structure. Its just used for internal purposes. * Remember every pattern infomarion based on "this.*" will be used by other functions * * @param pathObj path.parse() object containing usefull path information */ getPatternInfo: (pathObj, patternlab, isUnsubRun) => { const info = { - // 00-colors(.mustache) is subbed in 00-atoms-/00-global/00-colors + // 00-colors(.mustache) is subfolder in 00-atoms-/00-global/00-colors patternlab: patternlab, patternHasOwnDir: !isUnsubRun ? path.basename(pathObj.dir).replace(prefixMatcher, '') === diff --git a/packages/core/src/lib/readDocumentation.js b/packages/core/src/lib/readDocumentation.js index bfe35b983..2d66a7a7f 100644 --- a/packages/core/src/lib/readDocumentation.js +++ b/packages/core/src/lib/readDocumentation.js @@ -55,7 +55,10 @@ module.exports = function(pattern, patternlab) { pattern.links = markdownObject.links; } - if (markdownObject.hasOwnProperty('subbed') && !markdownObject.subbed) { + if ( + markdownObject.hasOwnProperty('subfolder') && + !markdownObject.subfolder + ) { // Reset to pattern without own pattern-directory pattern.resetSubbing(patternlab); } From fec2492c9bf2df563909932fc2db353a7d3d2d12 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Sun, 26 Apr 2020 21:50:33 +0200 Subject: [PATCH 010/330] #1143: Revert translation attempt --- packages/core/patternlab-config.json | 6 ------ packages/core/src/lib/object_factory.js | 6 +----- packages/core/src/lib/ui_builder.js | 15 ++------------- packages/edition-node/patternlab-config.json | 6 ------ .../src/scripts/components/pl-nav/src/NavLink.js | 4 ++-- .../src/scripts/components/pl-nav/src/NavList.js | 7 +++---- 6 files changed, 8 insertions(+), 36 deletions(-) diff --git a/packages/core/patternlab-config.json b/packages/core/patternlab-config.json index 31fcbf748..39eed54fd 100644 --- a/packages/core/patternlab-config.json +++ b/packages/core/patternlab-config.json @@ -75,12 +75,6 @@ "patternExportPatternPartials": [], "patternExportPreserveDirectoryStructure": true, "patternExportRaw": false, - "patternTranslations": { - "ViewAllSubGroup": "View all {sgName}", - "viewAllGroup": "View All", - "viewAllRoot": "All", - "rootName": "Root" - }, "serverOptions": { "wait": 1000 }, diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js index 36bcb9c6a..06e572527 100644 --- a/packages/core/src/lib/object_factory.js +++ b/packages/core/src/lib/object_factory.js @@ -237,11 +237,7 @@ Pattern.prototype = { } else { // Im Not quite shure about that but its better than empty node // TODO: verify - return pInfo.patternlab && - pInfo.patternlab.config.patternTranslations && - pInfo.patternlab.config.patternTranslations.rootName - ? _.kebabCase(pInfo.patternlab.config.patternTranslations.rootName) - : 'root'; + return 'root'; } }, diff --git a/packages/core/src/lib/ui_builder.js b/packages/core/src/lib/ui_builder.js index 4d4c371e4..e8707b97d 100644 --- a/packages/core/src/lib/ui_builder.js +++ b/packages/core/src/lib/ui_builder.js @@ -285,11 +285,7 @@ const ui_builder = function() { newSubTypeItem = { patternPartial: 'viewall-' + pattern.patternGroup + '-' + pattern.patternSubGroup, - patternName: - patternlab.config.patternTranslations && - patternlab.config.patternTranslations.viewAllGroup - ? patternlab.config.patternTranslations.viewAllGroup - : `View all`, + patternName: `View All`, patternPath: encodeURI(pattern.flatPatternPath + '/index.html'), patternType: pattern.patternType, patternSubtype: pattern.patternSubtype, @@ -326,14 +322,7 @@ const ui_builder = function() { if (isViewAllVariant) { patternType.patternItems.push({ patternPartial: `viewall-${pattern.patternGroup}-all`, - patternName: - patternlab.config.patternTranslations && - patternlab.config.patternTranslations.ViewAllSubGroup - ? patternlab.config.patternTranslations.ViewAllSubGroup.replace( - '{sgName}', - _.startCase(pattern.patternGroup) - ) - : `View all ${_.startCase(pattern.patternGroup)}`, + patternName: `View all ${_.startCase(pattern.patternGroup)}`, patternPath: encodeURI(pattern.patternGroup + '/index.html'), name: pattern.patternGroup, isDocPattern: true, diff --git a/packages/edition-node/patternlab-config.json b/packages/edition-node/patternlab-config.json index 67472a021..e5cef6811 100644 --- a/packages/edition-node/patternlab-config.json +++ b/packages/edition-node/patternlab-config.json @@ -75,12 +75,6 @@ "patternExportPatternPartials": [], "patternExportPreserveDirectoryStructure": true, "patternExportRaw": false, - "patternTranslations": { - "ViewAllSubGroup": "View all {sgName}", - "viewAllGroup": "View All", - "viewAllRoot": "All", - "rootName": "Root" - }, "serverOptions": { "wait": 1000 }, diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js index 80f3b26d9..7a7c742de 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js @@ -7,7 +7,7 @@ export const NavLink = props => { href={`patterns/${props.item.patternPath}`} className={`pl-c-nav__link pl-c-nav__link--sublink ${ - props.item.patternName === 'View All' + props.item.isDocPattern ? 'pl-c-nav__link--overview' : 'pl-c-nav__link--subsublink' } @@ -15,7 +15,7 @@ export const NavLink = props => { onClick={e => props.elem.handleClick(e, props.item.patternPartial)} data-patternpartial={props.item.patternPartial} > - {props.item.patternName === 'View All' && props.category + {props.item.isDocPattern && props.category ? `${props.category}` : props.item.patternName} {props.item.patternState && ( diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js index 0f5269041..adac59281 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js @@ -8,14 +8,13 @@ export const NavList = props => { const reorderedChildren = []; const nonViewAllItems = elem.noViewAll - ? children.filter(item => item.patternName !== 'View All') + ? children.filter(item => !item.isDocPattern) : children.filter( - item => - item.patternName !== 'View All' && !item.patternName.includes(' Docs') + item => !item.isDocPattern && !item.patternName.includes(' Docs') ); const viewAllItems = elem.noViewAll ? [] - : children.filter(item => item.patternName === 'View All'); + : children.filter(item => item.isDocPattern); reorderedChildren.push(...viewAllItems, ...nonViewAllItems); From 7dd18f9a39b12f9e644153e5957c6d018a58b321 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Sun, 26 Apr 2020 22:16:47 +0200 Subject: [PATCH 011/330] #1143: Fix naming of view-all links --- packages/core/src/lib/ui_builder.js | 4 ++-- .../src/scripts/components/pl-nav/pl-nav.js | 1 + .../src/scripts/components/pl-nav/src/NavLink.js | 2 +- .../src/scripts/components/pl-nav/src/NavList.js | 8 +++++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/core/src/lib/ui_builder.js b/packages/core/src/lib/ui_builder.js index e8707b97d..4fa560bfa 100644 --- a/packages/core/src/lib/ui_builder.js +++ b/packages/core/src/lib/ui_builder.js @@ -175,7 +175,7 @@ const ui_builder = function() { */ function addPatternType(patternlab, pattern) { patternlab.patternTypes.push({ - patternTypeLC: pattern.patternGroup.toLowerCase(), + patternTypeLC: _.kebabCase(pattern.patternGroup), patternTypeUC: _.startCase(pattern.patternGroup), patternType: pattern.patternType, patternTypeDash: pattern.patternGroup, //todo verify @@ -234,7 +234,7 @@ const ui_builder = function() { */ function addPatternSubType(patternlab, pattern) { const newSubType = { - patternSubtypeLC: pattern.patternSubGroup.toLowerCase(), + patternSubtypeLC: _.kebabCase(pattern.patternSubGroup), patternSubtypeUC: _.startCase(pattern.patternSubGroup), patternSubtype: pattern.patternSubType, patternSubtypeDash: pattern.patternSubGroup, //todo verify diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index b169bb54d..9a2226841 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -276,6 +276,7 @@ class Nav extends BaseComponent { {patternSubtype.patternSubtypeItems} diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js index 7a7c742de..6a55dabb3 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavLink.js @@ -16,7 +16,7 @@ export const NavLink = props => { data-patternpartial={props.item.patternPartial} > {props.item.isDocPattern && props.category - ? `${props.category}` + ? `${props.categoryName}` : props.item.patternName} {props.item.patternState && ( diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js index adac59281..df3665ff0 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/src/NavList.js @@ -4,7 +4,7 @@ import { NavLink } from './NavLink'; import { NavItem } from './NavItem'; export const NavList = props => { - const { children, category, elem } = props; + const { children, category, categoryName, elem } = props; const reorderedChildren = []; const nonViewAllItems = elem.noViewAll @@ -25,6 +25,7 @@ export const NavList = props => { )) ) : ( )} @@ -55,6 +56,7 @@ export const NavList = props => { From cf4f09276a9943f252b87648dd93ce43a3b4c9ec Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Mon, 27 Apr 2020 16:45:18 +0200 Subject: [PATCH 012/330] #1143 don't show all page if noViewall is active --- .../src/scripts/components/pl-nav/pl-nav.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index 2dbb2409e..8c93d59ed 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -307,19 +307,20 @@ class Nav extends BaseComponent { {(window.ishControls === undefined || window.ishControls.ishControlsHide === undefined || (window.ishControls.ishControlsHide['views-all'] !== true && - window.ishControls.ishControlsHide.all !== true)) && ( - - this.handleClick(e, 'all')} - href="styleguide/html/styleguide.html" - class="pl-c-nav__link pl-c-nav__link--pattern" - data-patternpartial="all" - tabindex="0" - > - All - - - )} + window.ishControls.ishControlsHide.all !== true)) && + !this.noViewAll && ( + + this.handleClick(e, 'all')} + href="styleguide/html/styleguide.html" + class="pl-c-nav__link pl-c-nav__link--pattern" + data-patternpartial="all" + tabindex="0" + > + All + + + )} ); } From bb5e8179e6b8553a6e1af0bede26db412b6c0b68 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Tue, 28 Apr 2020 19:08:06 +0200 Subject: [PATCH 013/330] fix(plugintabs): enabling multiple file formats #1163 --- .../dist/js/@pattern-lab-plugin-tab.js | 11 +++++- packages/plugin-tab/src/snippet.js | 34 +++++++------------ 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/plugin-tab/dist/js/@pattern-lab-plugin-tab.js b/packages/plugin-tab/dist/js/@pattern-lab-plugin-tab.js index 32869fb05..f1fcd7be3 100644 --- a/packages/plugin-tab/dist/js/@pattern-lab-plugin-tab.js +++ b/packages/plugin-tab/dist/js/@pattern-lab-plugin-tab.js @@ -6,6 +6,15 @@ window.PluginTab = { init: function() { //placeholder that will be replaced during configuation //most plugins could probably just implement logic here instead. - /*SNIPPETS*/ + function addPanels() { + /*SNIPPETS*/ + } + + // workaround to try recovering from load order race conditions + if (window.patternlab && window.patternlab.panels) { + addPanels(); + } else { + document.addEventListener('patternLab.pageLoad', addPanels); + } }, }; diff --git a/packages/plugin-tab/src/snippet.js b/packages/plugin-tab/src/snippet.js index 0439f7b18..08a592efd 100644 --- a/packages/plugin-tab/src/snippet.js +++ b/packages/plugin-tab/src/snippet.js @@ -1,21 +1,13 @@ -function addPanels() { - window.patternlab.panels.add({ - id: 'sg-panel-scss', - name: 'SCSS', - default: false, - templateID: 'pl-panel-template-code', - httpRequest: true, - httpRequestReplace: '.scss', - httpRequestCompleted: false, - prismHighlight: true, - language: 'scss', - keyCombo: 'ctrl+shift+z', - }); -} - -// workaround to try recovering from load order race conditions -if (window.patternlab && window.patternlab.panels) { - addPanels(); -} else { - document.addEventListener('patternLab.pageLoad', addPanels); -} +window.patternlab.panels.add({ + id: 'sg-panel-<>', + name: '<>', + default: window.config.defaultPatternInfoPanelCode && window.config.defaultPatternInfoPanelCode === "<>", + templateID: 'pl-panel-template-code', + httpRequest: true, + httpRequestReplace: '.<>', + httpRequestCompleted: false, + prismHighlight: true, + language: '<>'//, + /* TODO: We would need to find a way to enable keyCombo for multiple fields + keyCombo: 'ctrl+shift+z',*/ +}); From 82fac2944970cebc815a1cf14138101713320fe8 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Tue, 28 Apr 2020 19:30:11 +0200 Subject: [PATCH 014/330] chore(plugintab): corrected comment --- packages/plugin-tab/src/snippet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-tab/src/snippet.js b/packages/plugin-tab/src/snippet.js index 08a592efd..337f00fec 100644 --- a/packages/plugin-tab/src/snippet.js +++ b/packages/plugin-tab/src/snippet.js @@ -8,6 +8,6 @@ window.patternlab.panels.add({ httpRequestCompleted: false, prismHighlight: true, language: '<>'//, - /* TODO: We would need to find a way to enable keyCombo for multiple fields + /* TODO: We would need to find a way to enable keyCombo for multiple panels keyCombo: 'ctrl+shift+z',*/ }); From 93faadabbda9f26657ff4b500bc8e68b5e044d25 Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Tue, 28 Apr 2020 20:53:56 +0200 Subject: [PATCH 015/330] Add support for viewport resizing - Via manual input - Via shortcuts --- packages/uikit-workshop/src/icons/hay.svg | 3 + .../scripts/components/modal-styleguide.js | 22 +- .../src/scripts/components/modal-viewer.js | 24 +- .../src/scripts/components/pl-nav/pl-nav.js | 24 +- .../scripts/components/pl-search/pl-search.js | 24 +- .../lit-components/pl-header/pl-header.js | 23 +- .../pl-tools-menu/pl-tools-menu.js | 23 +- .../pl-viewport-size-list.iframe-helper.js | 24 ++ .../pl-viewport-size-list.js | 297 +++++++++++++++--- .../pl-viewport-size/pl-viewport-size.js | 49 ++- .../pl-viewport-size/pl-viewport-size.scss | 12 +- .../lit-components/pl-viewport/pl-viewport.js | 43 ++- .../pl-viewport/pl-viewport.scss | 3 + .../src/scripts/patternlab-pattern.modern.js | 1 + .../utils/iframe-msg-data-extraction.js | 21 ++ .../uikit-workshop/src/scripts/utils/index.js | 1 + 16 files changed, 417 insertions(+), 177 deletions(-) create mode 100644 packages/uikit-workshop/src/icons/hay.svg create mode 100644 packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js create mode 100644 packages/uikit-workshop/src/scripts/utils/iframe-msg-data-extraction.js diff --git a/packages/uikit-workshop/src/icons/hay.svg b/packages/uikit-workshop/src/icons/hay.svg new file mode 100644 index 000000000..466695e0d --- /dev/null +++ b/packages/uikit-workshop/src/icons/hay.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/uikit-workshop/src/scripts/components/modal-styleguide.js b/packages/uikit-workshop/src/scripts/components/modal-styleguide.js index c63907a8b..09e217139 100644 --- a/packages/uikit-workshop/src/scripts/components/modal-styleguide.js +++ b/packages/uikit-workshop/src/scripts/components/modal-styleguide.js @@ -5,6 +5,7 @@ import { panelsUtil } from './panels-util'; import './pl-copy-to-clipboard/pl-copy-to-clipboard'; +import { iframeMsgDataExtraction } from '../utils'; export const modalStyleguide = { // set up some defaults @@ -195,24 +196,11 @@ export const modalStyleguide = { /** * toggle the comment pop-up based on a user clicking on the pattern * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage - * @param {Object} event info + * + * @param {MessageEvent} e A message received by a target object. */ - receiveIframeMessage(event) { - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - - let data = {}; - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + receiveIframeMessage(e) { + const data = iframeMsgDataExtraction(e); // see if it got a path to replace if (data.event !== undefined && data.event === 'patternLab.patternQuery') { diff --git a/packages/uikit-workshop/src/scripts/components/modal-viewer.js b/packages/uikit-workshop/src/scripts/components/modal-viewer.js index cb29fd21e..3b9b736f0 100644 --- a/packages/uikit-workshop/src/scripts/components/modal-viewer.js +++ b/packages/uikit-workshop/src/scripts/components/modal-viewer.js @@ -4,7 +4,7 @@ */ import { scrollTo } from 'scroll-js'; -import { urlHandler, Dispatcher } from '../utils'; +import { urlHandler, Dispatcher, iframeMsgDataExtraction } from '../utils'; import { panelsViewer } from './panels-viewer'; import { store } from '../store.js'; // These are the actions needed by this element. @@ -283,25 +283,11 @@ export const modalViewer = { /** * toggle the comment pop-up based on a user clicking on the pattern * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage - * @param {Object} event info + * + * @param {MessageEvent} e A message received by a target object. */ - receiveIframeMessage(event) { - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - - let data = {}; - - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + receiveIframeMessage(e) { + const data = iframeMsgDataExtraction(e); if (data.event !== undefined && data.event === 'patternLab.pageLoad') { // @todo: refactor to better handle async iframe loading diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index 7311307b9..0f4026a29 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -7,6 +7,7 @@ const classNames = require('classnames'); import { getParents } from './get-parents'; import { store } from '../../store.js'; // redux store import { BaseComponent } from '../base-component.js'; +import { iframeMsgDataExtraction } from '../../utils'; import Mousetrap from 'mousetrap'; import 'url-search-params-polyfill'; @@ -89,24 +90,13 @@ class Nav extends BaseComponent { } } - receiveIframeMessage(event) { + /** + * + * @param {MessageEvent} e A message received by a target object. + */ + receiveIframeMessage(e) { const self = this; - - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - - let data = {}; - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + const data = iframeMsgDataExtraction(e); if (data.event !== undefined && data.event === 'patternLab.pageClick') { try { diff --git a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js index 02fe99f72..502999acc 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js +++ b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js @@ -10,7 +10,7 @@ import Mousetrap from 'mousetrap'; import VisuallyHidden from '@reach/visually-hidden'; import Autosuggest from 'react-autosuggest'; -import { urlHandler } from '../../utils'; +import { urlHandler, iframeMsgDataExtraction } from '../../utils'; import { BaseComponent } from '../base-component'; @define @@ -118,22 +118,12 @@ class Search extends BaseComponent { document.activeElement.blur(); } - receiveIframeMessage(event) { - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - - let data = {}; - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + /** + * + * @param {MessageEvent} e A message received by a target object. + */ + receiveIframeMessage(e) { + const data = iframeMsgDataExtraction(e); if (data.event !== undefined && data.event === 'patternLab.keyPress') { if (data.key === 'f' && data.metaKey === true) { diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js b/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js index a6f1addce..404fe38de 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js @@ -3,6 +3,7 @@ import { store } from '../../store.js'; // connect to redux import { ifDefined } from 'lit-html/directives/if-defined'; import { html } from 'lit-html'; import { BaseLitComponent } from '../../components/base-component'; +import { iframeMsgDataExtraction } from '../../utils'; import { customElement } from 'lit-element'; import Mousetrap from 'mousetrap'; import styles from './pl-header.scss?external'; @@ -142,24 +143,14 @@ class Header extends BaseLitComponent { `; } - receiveIframeMessage(event) { + /** + * + * @param {MessageEvent} e A message received by a target object. + */ + receiveIframeMessage(e) { const self = this; - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - - let data = {}; - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + const data = iframeMsgDataExtraction(e); if (data.event !== undefined && data.event === 'patternLab.pageClick') { try { diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js b/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js index 07cd2f9cc..9dcb89e49 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js @@ -2,7 +2,7 @@ import { define, props } from 'skatejs'; import Mousetrap from 'mousetrap'; import { h } from 'preact'; -import { urlHandler, patternName } from '../../utils'; +import { urlHandler, patternName, iframeMsgDataExtraction } from '../../utils'; import { store } from '../../store'; // redux store import styles from './pl-tools-menu.scss?external'; @@ -99,23 +99,14 @@ class ToolsMenu extends BaseLitComponent { this.toggle(); } - receiveIframeMessage(event) { + /** + * + * @param {MessageEvent} e A message received by a target object. + */ + receiveIframeMessage(e) { const self = this; - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - let data = {}; - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + const data = iframeMsgDataExtraction(e); if (data.event !== undefined && data.event === 'patternLab.pageClick') { try { diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js new file mode 100644 index 000000000..16c0e36b1 --- /dev/null +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js @@ -0,0 +1,24 @@ +import { targetOrigin } from '../../utils'; + +function sendPatternLabKeyEvent(e, name) { + try { + window.parent.postMessage( + JSON.stringify({ + event: `patternLab.${name}`, + key: e.key, + code: e.code, + }), + targetOrigin + ); + } catch (error) { + // @todo: how do we want to handle exceptions here? + } +} + +document.addEventListener('keydown', e => { + sendPatternLabKeyEvent(e, 'iframeKeyDownEvent'); +}); + +document.addEventListener('keyup', e => { + sendPatternLabKeyEvent(e, 'iframeKeyUpEvent'); +}); diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js index a93c5fb0e..8b09ad428 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js @@ -7,15 +7,38 @@ import { store } from '../../store.js'; // connect to redux import { Tooltip } from '../../components/pl-tooltip/pl-tooltip'; import VisuallyHidden from '@reach/visually-hidden'; -import { minViewportWidth, maxViewportWidth, getRandom } from '../../utils'; +import { + minViewportWidth, + maxViewportWidth, + getRandom, + iframeMsgDataExtraction, +} from '../../utils'; import styles from './pl-viewport-size-list.scss?external'; -// @todo: re-add keyboard shortcuts to these @define class ViewportSizes extends BaseComponent { static is = 'pl-viewport-sizes'; + sizes = Object.freeze({ + ZERO: 'zero', + SMALL: 'small', + MEDIUM: 'medium', + LARGE: 'large', + FULL: 'full', + RANDOM: 'random', + DISCO: 'disco', + HAY: 'hay', + }); + + discomode = false; + doscoId = null; + hayMode = false; + hayId = null; + + controlIsPressed = false; + altIsPressed = false; + _stateChanged(state) { this.triggerUpdate(); } @@ -33,6 +56,16 @@ class ViewportSizes extends BaseComponent { const state = store.getState(); const { ishControlsHide } = window.ishControls; this.ishControlsHide = ishControlsHide; + + // Remove EventListener or they will be added multiple times when reloading in serve mode + document.removeEventListener('keydown', this.handleKeyDownEvent); + document.removeEventListener('keyup', this.handleKeyCombination); + document.addEventListener('keydown', this.handleKeyDownEvent.bind(this)); + document.addEventListener('keyup', this.handleKeyCombination.bind(this)); + self.receiveIframeMessage = this.receiveIframeMessage.bind(self); + + window.removeEventListener('message', this.receiveIframeMessage); + window.addEventListener('message', this.receiveIframeMessage, false); } disconnectedCallback() { @@ -46,8 +79,14 @@ class ViewportSizes extends BaseComponent { resizeViewport(size) { if (this.iframe) { + this.killDisco(); + this.killHay(); + switch (size) { - case 'small': + case this.sizes.ZERO: + this.iframe.fullMode = false; + this.iframe.sizeiframe(0, true); + case this.sizes.SMALL: this.iframe.fullMode = false; this.iframe.sizeiframe( getRandom( @@ -59,7 +98,7 @@ class ViewportSizes extends BaseComponent { true ); break; - case 'medium': + case this.sizes.MEDIUM: this.iframe.fullMode = false; this.iframe.sizeiframe( getRandom( @@ -73,26 +112,187 @@ class ViewportSizes extends BaseComponent { true ); break; - case 'large': + case this.sizes.LARGE: this.iframe.fullMode = false; this.iframe.sizeiframe( getRandom( window.config.ishViewportRange !== undefined ? parseInt(window.config.ishViewportRange.l[0], 10) : 800, - maxViewportWidth + window.config.ishViewportRange !== undefined + ? parseInt(window.config.ishViewportRange.l[1], 10) + : 1000 ), true ); break; - case 'full': + case this.sizes.FULL: this.iframe.fullMode = true; this.iframe.sizeiframe(maxViewportWidth, true); break; + case this.sizes.RANDOM: + this.fullMode = false; + this.iframe.sizeiframe(this.getRangeRandomNumber(), true); + break; + case this.sizes.DISCO: + this.fullMode = false; + this.startDisco(); + break; + case this.sizes.HAY: + this.fullMode = false; + this.iframe.sizeiframe(minViewportWidth, true); + this.startHay(); + break; } } } + /** + * Get a random number between minViewportWidth and maxViewportWidth + */ + getRangeRandomNumber() { + return getRandom( + minViewportWidth, + // Do not evaluate a number higher than the clientWidth of the Iframe + // to prevent having max size multiple times + maxViewportWidth > this.iframe.clientWidth + ? this.iframe.clientWidth + : maxViewportWidth + ); + } + + /** + * Start the disco mode, which means in a specific interval resize + * the iframe random between minViewportWidth and maxViewportWidth + */ + startDisco() { + this.discoMode = true; + this.discoId = setInterval(this.disco.bind(this), 1000); + } + + /** + * Stop the disco mode + */ + killDisco() { + this.discoMode = false; + clearInterval(this.discoId); + this.discoID = null; + } + + /** + * Action to resize the Iframe in disco mode + */ + disco() { + this.iframe.sizeiframe(this.getRangeRandomNumber(), true); + } + + /** + * Start the Hay! mode, which means the iframe is growing slowly + * from minViewportWidth to maxViewportWidth + */ + startHay() { + this.hayMode = true; + this.hayId = setInterval(this.hay.bind(this), 100); + } + + /** + * Stop the Hay! Mode + */ + killHay() { + this.hayMode = false; + clearInterval(this.hayId); + this.hayId = null; + } + + /** + * Action to resize the Iframe in Hay! mode + */ + hay() { + this.iframe.sizeiframe(store.getState().app.viewportPx + 1, true); + } + + /** + * Litte workaround for Firefox Bug. + * + * On QWERTZ keyboards the e.altKey and e.ctrlKey will + * not be set if you click on a key that has a specific + * secondary or third char at ALT + ... + * + * @param {KeyboardEvent} e the keyevent + */ + handleKeyDownEvent(e) { + if (e.key === 'Control') { + this.controlIsPressed = true; + } + if (e.key === 'Alt') { + this.altIsPressed = true; + } + } + + /** + * https://patternlab.io/docs/advanced-keyboard-shortcuts.html + * + * Why use these specific key combinations? + * Works on QUERTZ, QUERTY and AZERTY keyboard and they are no + * reserved browser functionality key combinations. + * + * QUERTY https://en.wikipedia.org/wiki/QWERTY + * QUERTZ https://en.wikipedia.org/wiki/QWERTZ + * AZERTY https://en.wikipedia.org/wiki/AZERTY + * + * Chromium + * https://support.google.com/chrome/answer/157179?hl=en + * + * Firefox + * https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly + * + * @param {KeyboardEvent} e the keyevent + */ + handleKeyCombination(e) { + const ctrlKey = this.controlIsPressed; + const altKey = this.altIsPressed; + + if (ctrlKey && altKey && (e.code === 'Digit0' || e.code === 'Numpad0')) { + this.resizeViewport(this.sizes.ZERO); + } else if (ctrlKey && altKey && e.code === 'KeyS') { + this.resizeViewport(this.sizes.SMALL); + } else if (ctrlKey && altKey && e.code === 'KeyM') { + this.resizeViewport(this.sizes.MEDIUM); + } else if (ctrlKey && altKey && e.code === 'KeyL') { + this.resizeViewport(this.sizes.LARGE); + } else if (ctrlKey && altKey && e.code === 'KeyF') { + this.resizeViewport(this.sizes.FULL); + } else if (ctrlKey && altKey && e.code === 'KeyR') { + this.resizeViewport(this.sizes.RANDOM); + } else if (ctrlKey && altKey && e.code === 'KeyD') { + this.resizeViewport(this.sizes.DISCO); + } else if (ctrlKey && altKey && e.code === 'KeyH') { + this.resizeViewport(this.sizes.HAY); + } + + if (e.key === 'Control') { + this.controlIsPressed = false; + } + if (e.key === 'Alt') { + this.altIsPressed = false; + } + } + + /** + * Interpret and handle the received message input + * + * @param {MessageEvent} e A message received by a target object. + */ + receiveIframeMessage(e) { + const data = iframeMsgDataExtraction(e); + + if (data.event && data.event === 'patternLab.iframeKeyDownEvent') { + this.handleKeyDownEvent(data); + } else if (data.event && data.event === 'patternLab.iframeKeyUpEvent') { + this.handleKeyCombination(data); + } + } + rendered() { this.iframe = document.querySelector('pl-iframe'); this.iframeElem = document.querySelector('pl-iframe iframe'); @@ -116,7 +316,7 @@ class ViewportSizes extends BaseComponent { id: 'pl-size-s', ref: triggerRef, })} - onClick={e => this.resizeViewport('small')} + onClick={e => this.resizeViewport(this.sizes.SMALL)} dangerouslySetInnerHTML={{ __html: ` Resize viewport to small @@ -143,7 +343,7 @@ class ViewportSizes extends BaseComponent { id: 'pl-size-m', ref: triggerRef, })} - onClick={e => this.resizeViewport('medium')} + onClick={e => this.resizeViewport(this.sizes.MEDIUM)} dangerouslySetInnerHTML={{ __html: ` Resize viewport to medium @@ -170,7 +370,7 @@ class ViewportSizes extends BaseComponent { id: 'pl-size-l', ref: triggerRef, })} - onClick={e => this.resizeViewport('large')} + onClick={e => this.resizeViewport(this.sizes.LARGE)} dangerouslySetInnerHTML={{ __html: ` Resize viewport to large @@ -197,7 +397,7 @@ class ViewportSizes extends BaseComponent { id: 'pl-size-full', ref: triggerRef, })} - onClick={e => this.resizeViewport('full')} + onClick={e => this.resizeViewport(this.sizes.FULL)} dangerouslySetInnerHTML={{ __html: ` Resize viewport to full @@ -209,7 +409,7 @@ class ViewportSizes extends BaseComponent { )} - {/* {!this.ishControlsHide.random && ( + {!this.ishControlsHide.random && (
  • this.resizeViewport('random')} - > - Resize viewport to random - - + onClick={e => this.resizeViewport(this.sizes.RANDOM)} + dangerouslySetInnerHTML={{ + __html: ` + Resize viewport to random + + `, + }} + /> )}
  • - )} */} - {/* {!this.ishControlsHide.disco && ( + )} + {!this.ishControlsHide.disco && (
  • this.resizeViewport('disco')} - > - - Resize viewport using disco mode! - - - + onClick={e => this.resizeViewport(this.sizes.DISCO)} + dangerouslySetInnerHTML={{ + __html: ` + Resize viewport using disco mode! + + `, + }} + /> )}
  • - )} */} + )} {!this.ishControlsHide.hay && (
  • - + + {({ getTriggerProps, triggerRef }) => ( +
  • )} diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js index 9ca37136c..5637d4a70 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js @@ -19,12 +19,17 @@ class ViewportSize extends BaseLitComponent { }; } + constructor() { + super(); + this.state = { inputPixelValue: '' }; + } + connectedCallback() { super.connectedCallback && super.connectedCallback(); styles.use(); const state = store.getState(); - this.px = round(state.app.viewportPx, 0); - this.em = round(state.app.viewportEm, 1); + this.setPxEm(state); + this.iframe = document.querySelector('pl-iframe'); } disconnectedCallback() { @@ -33,8 +38,13 @@ class ViewportSize extends BaseLitComponent { } _stateChanged(state) { + this.setPxEm(state); + } + + setPxEm(state) { if (state.app.viewportPx !== this.px) { this.px = round(state.app.viewportPx, 0); + this.setState({ inputPixelValue: this.px }); } if (round(state.app.viewportEm, 1) !== this.em) { @@ -52,13 +62,40 @@ class ViewportSize extends BaseLitComponent { } } + handlePixelUpdate(e) { + // Prevent inserting letters or symbols + if (e.key.match(/\D+/g) && !(e.charCode === 13 || e.keyCode === 13)) { + e.preventDefault(); + } else { + this.setState({ inputPixelValue: e.target.value.replace(/\D+/g, '') }); + } + } + + handleSubmit(event) { + event.preventDefault(); + this.iframe.sizeiframe(this.state.inputPixelValue, true); + } + + handlePixelBlur(e) { + this.setState({ inputPixelValue: this.px }); + e.target.value = this.state.inputPixelValue; + } + render() { if (!window.__PRERENDER_INJECTED) { return html` -
    - ${this.px}px /  - ${this.em}em + +
    `; } diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss index be81c570a..cdf823dd6 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss @@ -18,6 +18,7 @@ pl-viewport-size { .pl-c-viewport-size { margin: 0; border: 0; + font-size: 0.85rem; padding: 0.3rem 0.25rem; line-height: 1; display: flex; @@ -35,13 +36,18 @@ pl-viewport-size { border: 0; border-radius: $pl-border-radius; background-color: transparent; - font-size: 0.75rem; color: inherit; width: auto; text-align: right; transition: all $pl-animate-quick ease-out; pointer-events: none; text-overflow: ellipsis; +} + +.pl-c-viewport-size__input-action { + max-width: 35px; + font-size: inherit; + pointer-events: auto; &::-moz-focus-inner { padding: 0; @@ -61,7 +67,6 @@ pl-viewport-size { outline-offset: -1px; } } - /** * Size input labels */ @@ -69,7 +74,6 @@ pl-viewport-size { display: block; margin: 0; padding: 0; - font-size: 0.7rem; - pointer-events: none; + cursor: pointer; } diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js index 99a456810..3e814d870 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js @@ -4,8 +4,13 @@ import { ifDefined } from 'lit-html/directives/if-defined'; import { store } from '../../store.js'; // connect to redux import { updateCurrentPattern, updateCurrentUrl } from '../../actions/app.js'; // redux actions import { updateViewportPx, updateViewportEm } from '../../actions/app.js'; // redux actions needed -import { minViewportWidth, maxViewportWidth } from '../../utils'; -import { urlHandler, patternName } from '../../utils'; +import { + minViewportWidth, + maxViewportWidth, + urlHandler, + patternName, + iframeMsgDataExtraction, +} from '../../utils'; import { html } from 'lit-html'; import { BaseLitComponent } from '../../components/base-component.js'; @@ -197,14 +202,16 @@ class IFrame extends BaseLitComponent { if (size < maxViewportWidth) { theSize = size; - } else if (size < minViewportWidth) { - //If the entered size is less than the minimum allowed viewport size, cap value at min vp size - theSize = minViewportWidth; } else { //If the entered size is larger than the max allowed viewport size, cap value at max vp size theSize = maxViewportWidth; } + if (size < minViewportWidth) { + //If the entered size is less than the minimum allowed viewport size, cap value at min vp size + theSize = minViewportWidth; + } + if (theSize > this.clientWidth) { theSize = this.clientWidth; } @@ -465,30 +472,20 @@ class IFrame extends BaseLitComponent { return false; } - // updates the nav after the iframed page tells the iframe it's done loading - receiveIframeMessage(event) { - // does the origin sending the message match the current host? if not dev/null the request - if ( - window.location.protocol !== 'file:' && - event.origin !== window.location.protocol + '//' + window.location.host - ) { - return; - } - - let data = {}; - try { - data = - typeof event.data !== 'string' ? event.data : JSON.parse(event.data); - } catch (e) { - // @todo: how do we want to handle exceptions here? - } + /** + * updates the nav after the iframed page tells the iframe it's done loading + * + * @param {MessageEvent} e A message received by a target object. + */ + receiveIframeMessage(e) { + const data = iframeMsgDataExtraction(e); // try to auto-correct for currentPattern data that doesn't always match with url // workaround for certain pages (especially view all pages) not always matching up internally with the expected current pattern key if (data.event !== undefined && data.event === 'patternLab.pageLoad') { try { const currentPattern = - this.sanitizePatternName(event.data.patternpartial) || + this.sanitizePatternName(data.patternpartial) || this.getPatternParam(); document.title = 'Pattern Lab - ' + currentPattern; diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss index c6ea632e2..c2fc119f6 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss @@ -39,6 +39,9 @@ pl-iframe { z-index: 0; flex-grow: 1; transition: height 0.3s ease; + // Prevent mobile overflow of pl-c-viewport__resizer-handle + overflow-x: hidden; + // @supports (position: sticky) { // top: 0; // } diff --git a/packages/uikit-workshop/src/scripts/patternlab-pattern.modern.js b/packages/uikit-workshop/src/scripts/patternlab-pattern.modern.js index fe0901868..08b09ad61 100755 --- a/packages/uikit-workshop/src/scripts/patternlab-pattern.modern.js +++ b/packages/uikit-workshop/src/scripts/patternlab-pattern.modern.js @@ -1,4 +1,5 @@ import './components/modal-styleguide'; import './components/pl-search/pl-search.iframe-helper'; import './components/pl-nav/pl-nav.iframe-helper'; +import './lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper'; import './utils/share-inner-iframe-data'; diff --git a/packages/uikit-workshop/src/scripts/utils/iframe-msg-data-extraction.js b/packages/uikit-workshop/src/scripts/utils/iframe-msg-data-extraction.js new file mode 100644 index 000000000..aa68d688b --- /dev/null +++ b/packages/uikit-workshop/src/scripts/utils/iframe-msg-data-extraction.js @@ -0,0 +1,21 @@ +/** + * Does the origin sending the message match the current host? + * if not dev/null the request + * + * @param {MessageEvent} e A message received by a target object. + */ +export function iframeMsgDataExtraction(e) { + if ( + window.location.protocol !== 'file:' && + event.origin !== window.location.protocol + '//' + window.location.host + ) { + return; + } + + try { + return typeof event.data !== 'string' ? event.data : JSON.parse(event.data); + } catch (e) { + // @todo: how do we want to handle exceptions here? + return {}; + } +} diff --git a/packages/uikit-workshop/src/scripts/utils/index.js b/packages/uikit-workshop/src/scripts/utils/index.js index d0a0a9b49..42c0c1491 100755 --- a/packages/uikit-workshop/src/scripts/utils/index.js +++ b/packages/uikit-workshop/src/scripts/utils/index.js @@ -9,3 +9,4 @@ export { targetOrigin } from './get-target-origin'; export { patternName } from './pattern-name'; export { minViewportWidth, maxViewportWidth } from './viewport-sizes'; export { getRandom } from './get-random'; +export { iframeMsgDataExtraction } from './iframe-msg-data-extraction'; From ad59246e9d2f6756e421e5d1e2ad78e5aacee0bf Mon Sep 17 00:00:00 2001 From: Josef Bredreck Date: Tue, 28 Apr 2020 21:09:45 +0200 Subject: [PATCH 016/330] #1167: Fix wrong event binding --- .../pl-viewport-size-list/pl-viewport-size-list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js index 8b09ad428..6b5110354 100644 --- a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js +++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js @@ -62,7 +62,7 @@ class ViewportSizes extends BaseComponent { document.removeEventListener('keyup', this.handleKeyCombination); document.addEventListener('keydown', this.handleKeyDownEvent.bind(this)); document.addEventListener('keyup', this.handleKeyCombination.bind(this)); - self.receiveIframeMessage = this.receiveIframeMessage.bind(self); + this.receiveIframeMessage = this.receiveIframeMessage.bind(this); window.removeEventListener('message', this.receiveIframeMessage); window.addEventListener('message', this.receiveIframeMessage, false); From 3e08fcb12b4e6e47993bb67d8309afd102095237 Mon Sep 17 00:00:00 2001 From: Ian Frost Date: Tue, 28 Apr 2020 16:33:58 -0400 Subject: [PATCH 017/330] Fix logo image path --- packages/docs/src/_includes/components/logo.njk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/_includes/components/logo.njk b/packages/docs/src/_includes/components/logo.njk index 6840071cb..b8b528064 100644 --- a/packages/docs/src/_includes/components/logo.njk +++ b/packages/docs/src/_includes/components/logo.njk @@ -1,7 +1,7 @@