From 3dfe791c022bfdce7419536bf1e1425a24fb3aa1 Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Thu, 26 Nov 2015 15:11:39 -0600 Subject: [PATCH 1/7] resolve issue with not hiding underscored patterns. fixes #165 --- CHANGELOG | 4 ++ builder/lineage_hunter.js | 2 +- builder/list_item_hunter.js | 2 +- builder/media_hunter.js | 2 +- builder/object_factory.js | 2 +- builder/parameter_hunter.js | 12 ++--- builder/pattern_assembler.js | 16 +++--- builder/pattern_exporter.js | 2 +- builder/patternlab.js | 2 +- builder/patternlab_grunt.js | 2 +- builder/patternlab_gulp.js | 2 +- builder/pseudopattern_hunter.js | 2 +- builder/style_modifier_hunter.js | 12 ++--- package.gulp.json | 2 +- package.json | 2 +- .../00-test/_ignored-pattern.mustache | 1 + test/pattern_assembler_tests.js | 51 +++++++++++++++++++ 17 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 test/files/_patterns/00-test/_ignored-pattern.mustache diff --git a/CHANGELOG b/CHANGELOG index 6e29f56f0..3e8d03629 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,9 @@ THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. +PL-node-v0.15.2 +- FIX: Resolve issue with not hiding underscored patterns. +- THX: Thanks @ivancamilov for reporting this regression. + PL-node-v0.15.1 - FIX: Resolve issue with styleModifiers not being replaced when the partial has spaces in it. - ADD: Support multiple styleModifier classes using the | pipe syntax diff --git a/builder/lineage_hunter.js b/builder/lineage_hunter.js index 9056cdeac..bd0951a63 100644 --- a/builder/lineage_hunter.js +++ b/builder/lineage_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/list_item_hunter.js b/builder/list_item_hunter.js index 87574eee9..7bd98b286 100644 --- a/builder/list_item_hunter.js +++ b/builder/list_item_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/media_hunter.js b/builder/media_hunter.js index d5ada91ce..0293626a0 100644 --- a/builder/media_hunter.js +++ b/builder/media_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/object_factory.js b/builder/object_factory.js index d1206866d..fff554e56 100644 --- a/builder/object_factory.js +++ b/builder/object_factory.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/parameter_hunter.js b/builder/parameter_hunter.js index 4732ad0a5..ea369a729 100644 --- a/builder/parameter_hunter.js +++ b/builder/parameter_hunter.js @@ -1,10 +1,10 @@ -/* - * patternlab-node - v0.15.1 - 2015 - * +/* + * patternlab-node - v0.15.2 - 2015 + * * Brian Muenzenmeyer, and the web community. - * Licensed under the MIT license. - * - * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. + * Licensed under the MIT license. + * + * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. * */ diff --git a/builder/pattern_assembler.js b/builder/pattern_assembler.js index 5363acbde..d6f5d2dc6 100644 --- a/builder/pattern_assembler.js +++ b/builder/pattern_assembler.js @@ -1,10 +1,10 @@ -/* - * patternlab-node - v0.15.1 - 2015 - * +/* + * patternlab-node - v0.15.2 - 2015 + * * Brian Muenzenmeyer, and the web community. - * Licensed under the MIT license. - * - * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. + * Licensed under the MIT license. + * + * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. * */ @@ -94,8 +94,8 @@ var filename = path.basename(file); var ext = path.extname(filename); - //ignore dotfiles and non-variant .json files - if(filename.charAt(0) === '.' || (ext === '.json' && filename.indexOf('~') === -1)){ + //ignore dotfiles, underscored files, and non-variant .json files + if(filename.charAt(0) === '.' || filename.charAt(0) === '_' || (ext === '.json' && filename.indexOf('~') === -1)){ return; } diff --git a/builder/pattern_exporter.js b/builder/pattern_exporter.js index 90915ec86..b985354f0 100644 --- a/builder/pattern_exporter.js +++ b/builder/pattern_exporter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab.js b/builder/patternlab.js index 9ea38d604..08d8f5e7e 100644 --- a/builder/patternlab.js +++ b/builder/patternlab.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab_grunt.js b/builder/patternlab_grunt.js index 843dd07f1..b5aefaee5 100644 --- a/builder/patternlab_grunt.js +++ b/builder/patternlab_grunt.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab_gulp.js b/builder/patternlab_gulp.js index d4014cb79..2c1b9f3d5 100644 --- a/builder/patternlab_gulp.js +++ b/builder/patternlab_gulp.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/pseudopattern_hunter.js b/builder/pseudopattern_hunter.js index 9f698650f..8db5a215d 100644 --- a/builder/pseudopattern_hunter.js +++ b/builder/pseudopattern_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.1 - 2015 + * patternlab-node - v0.15.2 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/style_modifier_hunter.js b/builder/style_modifier_hunter.js index 9baa6f0aa..7ef925160 100644 --- a/builder/style_modifier_hunter.js +++ b/builder/style_modifier_hunter.js @@ -1,10 +1,10 @@ -/* - * patternlab-node - v0.15.1 - 2015 - * +/* + * patternlab-node - v0.15.2 - 2015 + * * Brian Muenzenmeyer, and the web community. - * Licensed under the MIT license. - * - * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. + * Licensed under the MIT license. + * + * Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice. * */ diff --git a/package.gulp.json b/package.gulp.json index 099c8d907..8aab2cc3b 100644 --- a/package.gulp.json +++ b/package.gulp.json @@ -1,7 +1,7 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.15.1", + "version": "0.15.2", "devDependencies": { "browser-sync": "^2.10.0", "del": "^2.0.2", diff --git a/package.json b/package.json index 8d3953d22..f11e8ea3a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.15.1", + "version": "0.15.2", "devDependencies": { "bs-html-injector": "^3.0.0", "diveSync": "^0.3.0", diff --git a/test/files/_patterns/00-test/_ignored-pattern.mustache b/test/files/_patterns/00-test/_ignored-pattern.mustache new file mode 100644 index 000000000..ae9ed0946 --- /dev/null +++ b/test/files/_patterns/00-test/_ignored-pattern.mustache @@ -0,0 +1 @@ +
These aren't the patterns you are looking for.
diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index 36b6c3ea8..9c3b5736d 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -449,6 +449,57 @@ var expectedValue = '
{{message}} 2 3 {{message}}
'; test.equals(bookendPattern.extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), expectedValue.trim()); test.done(); + }, + 'processPatternIterative - ignores files that start with underscore' : function(test){ + //arrange + var diveSync = require('diveSync'); + var fs = require('fs-extra'); + var pa = require('../builder/pattern_assembler'); + var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; + var patternlab = {}; + patternlab.config = fs.readJSONSync('./config.json'); + patternlab.config.patterns = {source: patterns_dir}; + patternlab.data = fs.readJSONSync('./source/_data/data.json'); + patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json'); + patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8'); + patternlab.footer = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/footer.html', 'utf8'); + patternlab.patterns = []; + patternlab.data.link = {}; + patternlab.partials = {}; + + //act + diveSync(patterns_dir, + { + filter: function(path, dir){ + if(dir){ + var remainingPath = path.replace(patterns_dir, ''); + var isValidPath = remainingPath.indexOf('/_') === -1; + return isValidPath; + } + return true; + } + }, + function(err, file){ + //log any errors + if(err){ + console.log(err); + return; + } + + pattern_assembler.process_pattern_iterative(file.substring(2), patternlab); + } + ); + + //assert + var foundIgnoredPattern = false; + for(var i = 0; i < patternlab.patterns.length; i++){ + if(patternlab.patterns[i].fileName[0] === '_'){ + foundIgnoredPattern = true; + } + } + test.equals(foundIgnoredPattern, false); + test.done(); } }; }()); From 4faa3fae27db8f4a24abeffd3bc8e9f804e96b6a Mon Sep 17 00:00:00 2001 From: johngerome Date: Wed, 2 Dec 2015 10:08:32 +0800 Subject: [PATCH 2/7] Fix wrong class name for Error Input --- source/css/scss/base/_forms.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/css/scss/base/_forms.scss b/source/css/scss/base/_forms.scss index d121af100..75e4ad6c8 100644 --- a/source/css/scss/base/_forms.scss +++ b/source/css/scss/base/_forms.scss @@ -111,7 +111,7 @@ input[type="search"]::-webkit-search-decoration { } /* Validation */ -.has-error { +.is-error { border-color: $error; } .is-valid { @@ -135,4 +135,4 @@ input[type="search"]::-webkit-search-decoration { border: 0; border-left: 1px solid $gray; color: $gray; -} \ No newline at end of file +} From ed4f8dd63e2a5989cf04169e2e1dd1d377f55549 Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Fri, 4 Dec 2015 23:40:21 -0600 Subject: [PATCH 3/7] - ADD: Added a note in the README during installation to run with elevated privileges - THX: Thanks @RichardBray for the heads up - ADD: Added a Prerequisites section to the README --- CHANGELOG | 5 +++++ README.md | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 3e8d03629..4c3f9069c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,11 @@ THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. PL-node-v0.15.2 - FIX: Resolve issue with not hiding underscored patterns. - THX: Thanks @ivancamilov for reporting this regression. +- FIX: Fix misapplied error input class +- THX: Thanks @johngerome for the pull request! +- ADD: Added a note in the README during installation to run with elevated privileges +- THX: Thanks @RichardBray for the heads up +- ADD: Added a Prerequisites section to the README PL-node-v0.15.1 - FIX: Resolve issue with styleModifiers not being replaced when the partial has spaces in it. diff --git a/README.md b/README.md index c628bf065..b2353e58b 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,20 @@ The Node version of [Pattern Lab](http://patternlab.io/) is, at its core, a stat This repository contains the vanilla builder logic, grunt and gulp configurations, and some sample template/css/data to illustrate the power and flexibility of the tool. +### Prerequisites + +Make sure Node and npm are installed. A great guide can be found here: [https://docs.npmjs.com/getting-started/installing-node](https://docs.npmjs.com/getting-started/installing-node) + ### Download * Download the [latest release of patternlab-node](https://github.com/pattern-lab/patternlab-node/releases/latest) from Github * Via npm, run `npm install patternlab-node` (Note this will auto install the grunt version currently. see below) * **NOTE** Node version 4.X and 5.X have tentative support, citing [a lot of Windows issues](https://github.com/nodejs/node-gyp/issues/629), including [mine](https://github.com/pattern-lab/patternlab-node/issues/162). Upgrade node at your own risk until otherwise stated. I've tried to catalog some issues and troubleshooting steps on the [wiki](https://github.com/pattern-lab/patternlab-node/wiki/Windows-Issues). +### Troubleshooting Installs + +Make sure you are running your terminal/command line session as administrator. This could mean `sudo`, or opening the window with a right-click option. + ### Choose Your Adventure! Now Vanilla, Grunt & Gulp This repository ships with two `package.json` files, a `Gruntfile.js`, and a `gulpfile.js`. The default is grunt currently. The core builder is not dependent on either. From 800f3b95b1707b971f9a17ec726a2a903052840d Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Sat, 5 Dec 2015 00:53:52 -0600 Subject: [PATCH 4/7] added two patternState unit tests as part of #97 --- test/pattern_assembler_tests.js | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index 9c3b5736d..d6cdc1e28 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -500,6 +500,46 @@ } test.equals(foundIgnoredPattern, false); test.done(); + }, + 'setState - applies any patternState matching the pattern' : function(test){ + //arrange + var pa = require('../builder/pattern_assembler'); + var pattern_assembler = new pa(); + var patternlab = {}; + patternlab.config = {}; + patternlab.config.patternStates = {}; + patternlab.config.patternStates["homepage-emergency"] = "inprogress"; + + var pattern = { + patternName: "homepage-emergency" + }; + + //act + pattern_assembler.setPatternState(pattern, patternlab); + + //assert + test.equals(pattern.patternState, "inprogress"); + test.done(); + }, + 'setState - does not apply any patternState if nothing matches the pattern' : function(test){ + //arrange + var pa = require('../builder/pattern_assembler'); + var pattern_assembler = new pa(); + var patternlab = {}; + patternlab.config = {}; + patternlab.config.patternStates = {}; + patternlab.config.patternStates["homepage-emergency"] = "inprogress"; + + var pattern = { + patternName: "homepage" + }; + + //act + pattern_assembler.setPatternState(pattern, patternlab); + + //assert + test.equals(pattern.patternState, ""); + test.done(); } }; }()); From 277fdff44d1f651fe6122b2ad6eebfc1c856adfc Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Sat, 5 Dec 2015 01:00:50 -0600 Subject: [PATCH 5/7] delete this file, it's an artifact and should not be included --- public/data/annotations.js | 109 ------------------------------------- 1 file changed, 109 deletions(-) delete mode 100644 public/data/annotations.js diff --git a/public/data/annotations.js b/public/data/annotations.js deleted file mode 100644 index fc8209531..000000000 --- a/public/data/annotations.js +++ /dev/null @@ -1,109 +0,0 @@ -var comments = { -"comments" : [ - { - "el": "header[role=banner]", - "title" : "Masthead", - "comment": "The main header of the site doesn't take up too much screen real estate in order to keep the focus on the core content. It's using a linear CSS gradient instead of a background image to give greater design flexibility and reduce HTTP requests." - }, - { - "el": ".logo", - "title" : "Logo", - "comment": "The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don't support SVG images.

Further reading: Optimizing Web Experiences for High Resolution Screens

" - }, - { - "el": "#nav", - "title" : "Navigation", - "comment": "

Navigation for adaptive web experiences can be tricky. Top navigations are typical on desktop sites, but mobile screen sizes don't give us the luxury of space. We're dealing with this situation by creating a simple menu anchor that toggles the main navigation on small screens. This is just one method. Bagcheck and Contents Magazine add an anchor in the header that jumps users to the navigation which is placed in the footer. This solution works well because it doesn't require any Javascript in order to work. Other methods exist too. For example, ESPN's mobile navigation overlays the main content of the page.

The nav is only hidden when a certain level of javascript is supported in order to ensure that users with little/poor javascript support can still access the navigation. Once the screen size is large enough to accommodate the nav, we show the main navigation links and hide the menu anchor.

See also: Responsive Navigation Patterns

" - }, - { - "el": "input[type=search]", - "title" : "Search", - "comment": "

Search is an incredibly important priority, especially for mobile. It is a great idea to give users the ability to jump directly to what they are looking for without forcing them to wade through your site's navigation. Check out the Burton and Yelp mobile sites for great examples of experiences that prioritize search.

We're also using the HTML5 search input type, which is great for mobile devices that can bring up the appropriate virtual keyboard for many smartphones. And like the main header navigation, we're hiding the search form on small screens to save space. Clicking the search anchor toggles the form.

" - }, - { - "el": "#product-img nav", - "title" : "Image Navigation", - "comment": "

Instead of providing bullets, pagination or text-based image navigation, it's good e-commerce practice to show a preview of the various product views. By default the images simply link through to their larger counterparts, and if adequate javascript support exists, the images get loaded into the main image container.

" - }, - { - "el": "#img-container", - "title" : "Product Image", - "comment": "

The product image is the focal point of the page for good reason. It's typically what the user is there to see. The default markup simply includes the main product image, but that gets replaced with an image gallery if adequate javascript support exists.

We're also using Modernizr to detect if the browser supports touch events and if it does, we load in an excellent lightweight script called Swipe.js to create a touch-friendly image carousel. This allows users to swipe between product photos in a touch-friendly way. Because gestures are invisible, they might get overlooked, but clicking on the image navigation thumbnails animates the slideshow and hints to the user gestural interaction is available.

" - }, - { - "el": ".product-main header", - "title" : "Product Overview", - "comment": "The product overview appears in the markup before the image container in order to provide the user with the product name, how much it costs and how popular it is. Providing this information as soon as possible can help the user determine whether or not this is the product they're looking for without having to wait for the rest of the page to load." - }, - { - "el": ".star", - "title" : "Rating Stars", - "comment": "

We're using HTML special characters to display the product rating stars. We're using HTML characters instead of images to reduce the amount of images we're requesting and also maintaining crispness on high resolution screens. Not every device supports HTML special characters (Blackberry <=5.0 for example), but support is strong enough and the benefits are many.

See also: Optimizing Web Experiences for High Resolution Screens

" - }, - { - "el": ".review-count", - "title" : "Review Count", - "comment": "This is a simple anchor link that points to the review section of the page. This may seem like a small detail, but consider a mobile use case. Users can be in stores looking at the physical product, and 79% of smartphone consumers use their phones to help with shopping. They might be interested in buying in-store but turn to their phones to verify its popularity and quality. Making it easy for uses to read product reviews on small screens can help drive more sales, both online and offline.

While not incorporated yet, it would be easy to load the reviews for small screens on demand, thereby saving a step.

" - }, - { - "el": ".qty-field", - "title" : "Quantity Field", - "comment": "We're using the HTML5 number input type, which brings up the appropriate virtual keyboard for many mobile browsers. To increase usability, the input labels are using the \"for\" attribute, which focuses the cursor in the form field when clicked. However, iOS doesn't honor \"for\" default functionality, so we're adding \"cursor: pointer\" to the labels to get Mobile Safari to behave properly." - }, - { - "el": ".size-field", - "title" : "Size Dropdown", - "comment": "We're using a basic select menu to choose the size, which is commonplace for any e-commerce site. Select menus can be especially difficult to style and can vary greatly in behavior between platforms. Keep this in mind when creating " - }, - { - "el": ".submit-form", - "title" : "Add to Cart button", - "comment": "The add to cart button is the primary user action on the page. That's why it's large and in charge and very prominently placed on the page. The button is using box-shadows and rounded corners to create an attractive button that will hopefully get plenty of clicks." - }, - { - "el": ".share-btn", - "title" : "Share button", - "comment": "It seems like everything has a share button on it these days. And for good reason. Sharing content and products on social networks can be a great way to increase exposure. However, tacking on tons of social widgets adds a lot of overhead, which can be extremely detrimental to the site's performance. Including a simple share link that loads the heavy widgets only when requested is one way to keep pages fast and social. Check out Target's mobile site for an example of a site that isolates share functionality in a separate page fragment." - }, - { - "el": ".find-nearby", - "title" : "Geolocation", - "comment": "One of the most important aspects of the mobile context is location. We carry our mobile devices with us everywhere. Using geolocation we can tap into the user's location to deliver an enhanced experience. In this case we're giving them a chance to check out what stores nearby might sell this product. The geolocation API is well supported in mobile browsers as well as desktop browsers. We're using Modernizr to detect for geolocation support and if its support, we ask the user for their latitude and longitude. If the browser does not support geolocation, the default experience could take the user to a simple web form asking for a ZIP code. Check out Tiffany's mobile site store locator for an example of geolocation in action." - }, - { - "el": "#p-desc", - "title" : "Product Description", - "comment": "A product description is an essential part of any e-commerce experience. Descriptions offer tangible details that inform and persuade, and the tone can help support the physical product. Provide relevant information clearly and concisely. Check out the Android design guide for some tips on how to keep copy short and extremely effective." - }, - { - "el": "#related-products", - "title" : "Related Products", - "comment": "

Related products are obviously an important aspect of e-commerce sites as they drive awareness of other similar products and can lead to more purchases. However, including a lot of auxiliary content can bog down the site performance, which is especially crucial on mobile. On slow connections, the presence of this extra content might slow down the user experience enough that the user gives up.

We're handling the issue by conditionally loading the auxiliary content.

By default, the related item link simply clicks through to an HTML fragment containing the related products. The content is still accessible, even on devices with poor or no javascript support. When the user clicks on the related products on small screens, the content gets dynamically loaded inline and the link becomes a toggler for the content. Once the experience reaches a certain width breakpoint, we then load in the content. However, screen size != fast connection, so we should keep our eyes on the emerging navigator.connection to better gauge real connection speed.

See also: An Ajax-Include Pattern for Modular Content

All these wonderful t-shirts are retired/rejected Busted Tees, graciously donated to this demo by Will Schneider.

" - }, - { - "el": "#reviews", - "title" : "Reviews", - "comment": "Reviews are incredibly influential on a user's decision to purchase a product or pass on it. Also, because we carry our mobile phones with us everywhere, we use them to inform our in-store purchased. 70% of smartphone owners use them while in brick and mortar stores, and often times they're looking for reviews to give them the green light to buy.

Only the primary product content gets loaded by default, and the reviews exist as their own separate HTML fragment. The reviews remain accessible and don't get loaded until we conditionally load them when the screen is large enough or small screen users click the reviews link. This keeps things nimble while still providing access to the valuable reviews.

See also: An Ajax-Include Pattern for Modular Content

" - }, - { - "el": "#p-reviews .btn", - "title" : "More Reviews Button", - "comment": "

All reviews aren't loaded by default in order to keep the site performance in top shape. Ultimately, this button could be replaced with a lazy-loading solution to remove the need for the button.

" - }, - { - "el": ".footer .nav", - "title" : "Footer Nav", - "comment": "

Repetition of elements isn't a bad thing, especially with potentially long scrolling pages on mobile. Providing access to the main site navigation is a good way for the user to jump off to another section and avoids leaving them with a dead end. Also, some mobile sites like Bagcheck and Contents Magazine keep the primary navigation at the footer and simply link to it with an anchor in the header. That way the nav stays accessible but the focus stays on on the core page content.

" - }, - { - "el": ".tel", - "title" : "Customer Service Number", - "comment": "

We sometimes forget that mobile phones can make phone calls. Whether a user is having trouble with the site or simply has some questions about the product he's about to buy, it's a smart decision to provide a clickable phone number to facilitate that call. What happens when desktops and other non-phone devices click on the tel link? Well, some devices (like iPads and other tablets) ask the user if they'd like to add the number to their contact list, other desktops open 3rd party VoIP programs like Skype, and others simply give an error message.

" - }, - { - "el": ".top", - "title" : "Back to Top Link", - "comment": "

Back to top links are simple yet underrated. They provide users with an easy way back up to the top of the page with minimum effort. This is especially helpful on mobile devices, which tend to have long scrolling pages.

We're using an HTML character for the back to top arrow in order to reduce image elements and keep things looking crisp on high res displays.

" - } -] -}; \ No newline at end of file From a66d0a850bbeb547785013b05f10508ed568705d Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Mon, 7 Dec 2015 23:53:13 -0600 Subject: [PATCH 6/7] Made pseudopattern_hunter a bit less hardcoded added unit test for pseudopattern generation fixed a bug where pseudopatterns were being added to the UI twice explicitly sorted patterns before UI build setting version to v0.16.0 --- .gitignore | 1 + CHANGELOG | 5 +- builder/lineage_hunter.js | 2 +- builder/list_item_hunter.js | 2 +- builder/media_hunter.js | 2 +- builder/object_factory.js | 2 +- builder/parameter_hunter.js | 2 +- builder/pattern_assembler.js | 12 ++-- builder/pattern_exporter.js | 2 +- builder/patternlab.js | 14 +++- builder/patternlab_grunt.js | 2 +- builder/patternlab_gulp.js | 2 +- builder/pseudopattern_hunter.js | 10 +-- builder/style_modifier_hunter.js | 2 +- package.gulp.json | 2 +- package.json | 2 +- .../_patterns/00-test/03-styled-atom~alt.json | 3 + test/pattern_assembler_tests.js | 66 +++++++++++++++++-- test/pseudopattern_hunter_tests.js | 45 +++++++++++++ 19 files changed, 147 insertions(+), 31 deletions(-) create mode 100644 test/files/_patterns/00-test/03-styled-atom~alt.json create mode 100644 test/pseudopattern_hunter_tests.js diff --git a/.gitignore b/.gitignore index 7200b256a..08b9a2f83 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ public/index.html public/styleguide.html public/styleguide/html/styleguide.html public/css/* +public/data/* public/fonts/* public/js/* public/images/* diff --git a/CHANGELOG b/CHANGELOG index 4c3f9069c..fd73f8cc4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. -PL-node-v0.15.2 +PL-node-v0.16.0 - FIX: Resolve issue with not hiding underscored patterns. - THX: Thanks @ivancamilov for reporting this regression. - FIX: Fix misapplied error input class @@ -8,6 +8,9 @@ PL-node-v0.15.2 - ADD: Added a note in the README during installation to run with elevated privileges - THX: Thanks @RichardBray for the heads up - ADD: Added a Prerequisites section to the README +- ADD: Added unit tests for pattern states and pseudopatterns +- CHG: Changed pseudopattern generation to use config.patterns.source directory instead of hardcode +- CHG: Explicitly sorting patterns by name prior to building the UI PL-node-v0.15.1 - FIX: Resolve issue with styleModifiers not being replaced when the partial has spaces in it. diff --git a/builder/lineage_hunter.js b/builder/lineage_hunter.js index bd0951a63..a01d2c641 100644 --- a/builder/lineage_hunter.js +++ b/builder/lineage_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/list_item_hunter.js b/builder/list_item_hunter.js index 7bd98b286..690079561 100644 --- a/builder/list_item_hunter.js +++ b/builder/list_item_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/media_hunter.js b/builder/media_hunter.js index 0293626a0..b939e3b39 100644 --- a/builder/media_hunter.js +++ b/builder/media_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/object_factory.js b/builder/object_factory.js index fff554e56..d53587ec1 100644 --- a/builder/object_factory.js +++ b/builder/object_factory.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/parameter_hunter.js b/builder/parameter_hunter.js index ea369a729..a0e78e6f8 100644 --- a/builder/parameter_hunter.js +++ b/builder/parameter_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/pattern_assembler.js b/builder/pattern_assembler.js index d6f5d2dc6..ccf85e144 100644 --- a/builder/pattern_assembler.js +++ b/builder/pattern_assembler.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -46,7 +46,7 @@ } function setState(pattern, patternlab){ - if(patternlab.config.patternStates[pattern.patternName]){ + if(patternlab.config.patternStates && patternlab.config.patternStates[pattern.patternName]){ pattern.patternState = patternlab.config.patternStates[pattern.patternName]; } else{ pattern.patternState = ""; @@ -102,13 +102,9 @@ //make a new Pattern Object var currentPattern = new of.oPattern(file, subdir, filename); - //if file is named in the syntax for variants + //if file is named in the syntax for variants, no need to process further + //processPatternRecursive() will run find_pseudopatterns() and look at each pattern for a variant if(ext === '.json' && filename.indexOf('~') > -1){ - //add current pattern to patternlab object with minimal data - //processPatternRecursive() will run find_pseudopatterns() to fill out - //the object in the next diveSync - addPattern(currentPattern, patternlab); - //no need to process further return; } diff --git a/builder/pattern_exporter.js b/builder/pattern_exporter.js index b985354f0..7fc1e37ad 100644 --- a/builder/pattern_exporter.js +++ b/builder/pattern_exporter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab.js b/builder/patternlab.js index 08d8f5e7e..d40956ca2 100644 --- a/builder/patternlab.js +++ b/builder/patternlab.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -211,6 +211,18 @@ var patternlab_engine = function () { //build the patternlab website var patternlabSiteTemplate = fs.readFileSync('./source/_patternlab-files/index.mustache', 'utf8'); + //sort all patterns explicitly. + patternlab.patterns = patternlab.patterns.sort(function(a,b){ + if (a.name > b.name) { + return 1; + } + if (a.name < b.name) { + return -1; + } + // a must be equal to b + return 0; + }); + //loop through all patterns.to build the navigation //todo: refactor this someday for(var i = 0; i < patternlab.patterns.length; i++){ diff --git a/builder/patternlab_grunt.js b/builder/patternlab_grunt.js index b5aefaee5..606127614 100644 --- a/builder/patternlab_grunt.js +++ b/builder/patternlab_grunt.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab_gulp.js b/builder/patternlab_gulp.js index 2c1b9f3d5..5db996f66 100644 --- a/builder/patternlab_gulp.js +++ b/builder/patternlab_gulp.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/pseudopattern_hunter.js b/builder/pseudopattern_hunter.js index 8db5a215d..b4e69867e 100644 --- a/builder/pseudopattern_hunter.js +++ b/builder/pseudopattern_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -28,7 +28,7 @@ //look for a pseudo pattern by checking if there is a file containing same name, with ~ in it, ending in .json var needle = currentPattern.subdir + '/' + currentPattern.fileName + '~*.json'; var pseudoPatterns = glob.sync(needle, { - cwd: 'source/_patterns/', //relative to gruntfile + cwd: patternlab.config.patterns.source + '/', debug: false, nodir: true, }); @@ -41,14 +41,14 @@ console.log('found pseudoPattern variant of ' + currentPattern.key); } - //we want to do everything we normally would here, except instead head the pseudoPattern data - var variantFileData = fs.readJSONSync('source/_patterns/' + pseudoPatterns[i]); + //we want to do everything we normally would here, except instead read the pseudoPattern data + var variantFileData = fs.readJSONSync(patternlab.config.patterns.source + '/' + pseudoPatterns[i]); //extend any existing data with variant data variantFileData = pattern_assembler.merge_data(currentPattern.jsonFileData, variantFileData); var variantName = pseudoPatterns[i].substring(pseudoPatterns[i].indexOf('~') + 1).split('.')[0]; - var variantFilePath = 'source/_patterns/' + currentPattern.subdir + '/' + currentPattern.fileName + '~' + variantName + '.json'; + var variantFilePath = patternlab.config.patterns.source + '/' + currentPattern.subdir + '/' + currentPattern.fileName + '~' + variantName + '.json'; var variantFileName = currentPattern.fileName + '-' + variantName + '.'; var patternVariant = new of.oPattern(variantFilePath, currentPattern.subdir, variantFileName, variantFileData); diff --git a/builder/style_modifier_hunter.js b/builder/style_modifier_hunter.js index 7ef925160..c38ada4fd 100644 --- a/builder/style_modifier_hunter.js +++ b/builder/style_modifier_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.15.2 - 2015 + * patternlab-node - v0.16.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/package.gulp.json b/package.gulp.json index 8aab2cc3b..313d4edf1 100644 --- a/package.gulp.json +++ b/package.gulp.json @@ -1,7 +1,7 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.15.2", + "version": "0.16.0", "devDependencies": { "browser-sync": "^2.10.0", "del": "^2.0.2", diff --git a/package.json b/package.json index f11e8ea3a..516481505 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.15.2", + "version": "0.16.0", "devDependencies": { "bs-html-injector": "^3.0.0", "diveSync": "^0.3.0", diff --git a/test/files/_patterns/00-test/03-styled-atom~alt.json b/test/files/_patterns/00-test/03-styled-atom~alt.json new file mode 100644 index 000000000..d4595ffd0 --- /dev/null +++ b/test/files/_patterns/00-test/03-styled-atom~alt.json @@ -0,0 +1,3 @@ +{ + "message": "alternateMessage" +} diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index d6cdc1e28..2519b87ba 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -290,6 +290,7 @@ //arrange var fs = require('fs-extra'); var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; var pl = {}; pl.config = {}; @@ -297,7 +298,7 @@ pl.data.link = {}; pl.config.debug = false; pl.patterns = []; - var patterns_dir = './test/files/_patterns'; + pl.config.patterns = { source: patterns_dir}; var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); @@ -322,6 +323,7 @@ //arrange var fs = require('fs-extra'); var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; var pl = {}; pl.config = {}; @@ -329,7 +331,7 @@ pl.data.link = {}; pl.config.debug = false; pl.patterns = []; - var patterns_dir = './test/files/_patterns'; + pl.config.patterns = { source: patterns_dir}; var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); @@ -354,6 +356,7 @@ //arrange var fs = require('fs-extra'); var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; var pl = {}; pl.config = {}; @@ -361,7 +364,7 @@ pl.data.link = {}; pl.config.debug = false; pl.patterns = []; - var patterns_dir = './test/files/_patterns'; + pl.config.patterns = { source: patterns_dir}; var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); @@ -386,6 +389,7 @@ //arrange var fs = require('fs-extra'); var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; var pl = {}; pl.config = {}; @@ -393,7 +397,7 @@ pl.data.link = {}; pl.config.debug = false; pl.patterns = []; - var patterns_dir = './test/files/_patterns'; + pl.config.patterns = { source: patterns_dir}; var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); @@ -420,6 +424,7 @@ //arrange var fs = require('fs-extra'); var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; var pl = {}; pl.config = {}; @@ -427,7 +432,7 @@ pl.data.link = {}; pl.config.debug = false; pl.patterns = []; - var patterns_dir = './test/files/_patterns'; + pl.config.patterns = { source: patterns_dir}; var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); atomPattern.template = fs.readFileSync(patterns_dir + '/00-test/03-styled-atom.mustache', 'utf8'); @@ -501,6 +506,57 @@ test.equals(foundIgnoredPattern, false); test.done(); }, + 'processPatternIterative - ignores files that are variants' : function(test){ + //arrange + var diveSync = require('diveSync'); + var fs = require('fs-extra'); + var pa = require('../builder/pattern_assembler'); + var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns'; + var patternlab = {}; + patternlab.config = fs.readJSONSync('./config.json'); + patternlab.config.patterns = {source: patterns_dir}; + patternlab.data = fs.readJSONSync('./source/_data/data.json'); + patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json'); + patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8'); + patternlab.footer = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/footer.html', 'utf8'); + patternlab.patterns = []; + patternlab.data.link = {}; + patternlab.partials = {}; + + //act + diveSync(patterns_dir, + { + filter: function(path, dir){ + if(dir){ + var remainingPath = path.replace(patterns_dir, ''); + var isValidPath = remainingPath.indexOf('/_') === -1; + return isValidPath; + } + return true; + } + }, + function(err, file){ + //log any errors + if(err){ + console.log(err); + return; + } + + pattern_assembler.process_pattern_iterative(file.substring(2), patternlab); + } + ); + + //assert + var foundVariant = false; + for(var i = 0; i < patternlab.patterns.length; i++){ + if(patternlab.patterns[i].fileName.indexOf('~') > -1){ + foundVariant = true; + } + } + test.equals(foundVariant, false); + test.done(); + }, 'setState - applies any patternState matching the pattern' : function(test){ //arrange var pa = require('../builder/pattern_assembler'); diff --git a/test/pseudopattern_hunter_tests.js b/test/pseudopattern_hunter_tests.js new file mode 100644 index 000000000..5a50dbcdd --- /dev/null +++ b/test/pseudopattern_hunter_tests.js @@ -0,0 +1,45 @@ +(function () { + "use strict"; + + var pha = require('../builder/pseudopattern_hunter'); + var pa = require('../builder/pattern_assembler'); + var object_factory = require('../builder/object_factory'); + + exports['pseudopattern_hunter'] = { + 'pseudpattern found and added as a pattern' : function(test){ + //arrange + var fs = require('fs-extra'); + var pattern_assembler = new pa(); + var pseudopattern_hunter = new pha(); + var patterns_dir = './test/files/_patterns/'; + + var pl = {}; + pl.config = {}; + pl.data = {}; + pl.data.link = {}; + pl.config.debug = false; + pl.patterns = []; + pl.config.patterns = { source: patterns_dir}; + pl.config.patternStates = {}; + + var atomPattern = new object_factory.oPattern('test/files/_patterns/00-test/03-styled-atom.mustache', '00-test', '03-styled-atom.mustache'); + atomPattern.template = fs.readFileSync(patterns_dir + '00-test/03-styled-atom.mustache', 'utf8'); + atomPattern.extendedTemplate = atomPattern.template; + atomPattern.stylePartials = pattern_assembler.find_pattern_partials_with_style_modifiers(atomPattern); + + pl.patterns.push(atomPattern); + + //act + var patternCountBefore = pl.patterns.length; + pseudopattern_hunter.find_pseudopatterns(atomPattern, pl); + + //assert + test.equals(patternCountBefore + 1, pl.patterns.length); + test.equals(pl.patterns[1].key, 'test-styled-atom-alt'); + test.equals(pl.patterns[1].extendedTemplate.replace(/\s\s+/g, ' ').replace(/\n/g, ' ').trim(), ' {{message}} '); + test.equals(JSON.stringify(pl.patterns[1].jsonFileData), JSON.stringify({"message": "alternateMessage"})); + + test.done(); + } + } +}()); From ddfd363baa94ab49855fa0ba4e84fa747e054c59 Mon Sep 17 00:00:00 2001 From: BRIAN MUENZENMEYER Date: Tue, 8 Dec 2015 23:42:24 -0600 Subject: [PATCH 7/7] Support for pattern link.* shortcut inside pattern data objects. Unit test to cover this Resolves #171 Marking this version 1.0.0 - having achieved broad feature parity with PL PHP v1 --- CHANGELOG | 5 +- builder/lineage_hunter.js | 2 +- builder/list_item_hunter.js | 2 +- builder/media_hunter.js | 2 +- builder/object_factory.js | 2 +- builder/parameter_hunter.js | 2 +- builder/pattern_assembler.js | 36 +++++++++++- builder/pattern_exporter.js | 2 +- builder/patternlab.js | 7 ++- builder/patternlab_grunt.js | 2 +- builder/patternlab_gulp.js | 2 +- builder/pseudopattern_hunter.js | 2 +- builder/style_modifier_hunter.js | 2 +- package.gulp.json | 2 +- package.json | 2 +- test/files/_patterns/00-test/link.mustache | 1 + test/files/_patterns/00-test/nav.json | 11 ++++ test/files/_patterns/00-test/nav.mustache | 9 +++ test/pattern_assembler_tests.js | 66 ++++++++++++++++++++++ 19 files changed, 144 insertions(+), 15 deletions(-) create mode 100644 test/files/_patterns/00-test/link.mustache create mode 100644 test/files/_patterns/00-test/nav.json create mode 100644 test/files/_patterns/00-test/nav.mustache diff --git a/CHANGELOG b/CHANGELOG index fd73f8cc4..c01f4e782 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. -PL-node-v0.16.0 +PL-node-v1.0.0 - FIX: Resolve issue with not hiding underscored patterns. - THX: Thanks @ivancamilov for reporting this regression. - FIX: Fix misapplied error input class @@ -11,6 +11,9 @@ PL-node-v0.16.0 - ADD: Added unit tests for pattern states and pseudopatterns - CHG: Changed pseudopattern generation to use config.patterns.source directory instead of hardcode - CHG: Explicitly sorting patterns by name prior to building the UI +- ADD: Added ability to specify link.* urls inside data objects +- CHG: Incremented version to 1.0.0. Achieved near-parity with PL PHP 1! +- THX: Thanks to each and every person who cared about Pattern Lab Node! - Brian PL-node-v0.15.1 - FIX: Resolve issue with styleModifiers not being replaced when the partial has spaces in it. diff --git a/builder/lineage_hunter.js b/builder/lineage_hunter.js index a01d2c641..916eddb93 100644 --- a/builder/lineage_hunter.js +++ b/builder/lineage_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/list_item_hunter.js b/builder/list_item_hunter.js index 690079561..f553f32c2 100644 --- a/builder/list_item_hunter.js +++ b/builder/list_item_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/media_hunter.js b/builder/media_hunter.js index b939e3b39..e7eb70a15 100644 --- a/builder/media_hunter.js +++ b/builder/media_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/object_factory.js b/builder/object_factory.js index d53587ec1..6823d94a7 100644 --- a/builder/object_factory.js +++ b/builder/object_factory.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/parameter_hunter.js b/builder/parameter_hunter.js index a0e78e6f8..e38481beb 100644 --- a/builder/parameter_hunter.js +++ b/builder/parameter_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/pattern_assembler.js b/builder/pattern_assembler.js index ccf85e144..f175dc115 100644 --- a/builder/pattern_assembler.js +++ b/builder/pattern_assembler.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -54,6 +54,7 @@ } function addPattern(pattern, patternlab){ + //add the link to the global object patternlab.data.link[pattern.patternGroup + '-' + pattern.patternName] = '/patterns/' + pattern.patternLink; //only push to array if the array doesn't contain this pattern @@ -317,6 +318,36 @@ return o; } + //look for pattern links included in data files. + //these will be in the form of link.* WITHOUT {{}}, which would still be there from direct pattern inclusion + function parseDataLinks(patternlab){ + + //loop through all patterns + for (var i = 0; i < patternlab.patterns.length; i++){ + var pattern = patternlab.patterns[i]; + //look for link.* such as link.pages-blog as a value + var linkRE = /link.[A-z0-9-_]+/g; + //convert to string for easier searching + var dataObjAsString = JSON.stringify(pattern.jsonFileData); + var linkMatches = dataObjAsString.match(linkRE); + + //if no matches found, escape current loop iteration + if(linkMatches === null) { continue; } + + for(var i = 0; i < linkMatches.length; i++){ + //for each match, find the expanded link within the already constructed patternlab.data.link object + var expandedLink = patternlab.data.link[linkMatches[i].split('.')[1]]; + if(patternlab.config.debug){ + console.log('expanded data link from ' + linkMatches[i] + ' to ' + expandedLink + ' inside ' + pattern.key); + } + //replace value with expandedLink on the pattern + dataObjAsString = dataObjAsString.replace(linkMatches[i], expandedLink); + } + //write back to data on the pattern + pattern.jsonFileData = JSON.parse(dataObjAsString); + } + } + return { find_pattern_partials: function(pattern){ return findPartials(pattern); @@ -356,6 +387,9 @@ }, is_object_empty: function(obj){ return isObjectEmpty(obj); + }, + parse_data_links: function(patternlab){ + parseDataLinks(patternlab); } }; diff --git a/builder/pattern_exporter.js b/builder/pattern_exporter.js index 7fc1e37ad..ddbf74023 100644 --- a/builder/pattern_exporter.js +++ b/builder/pattern_exporter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab.js b/builder/patternlab.js index d40956ca2..01850e29c 100644 --- a/builder/patternlab.js +++ b/builder/patternlab.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -91,6 +91,10 @@ var patternlab_engine = function () { pattern_assembler.process_pattern_iterative(file.substring(2), patternlab); }); + //now that all the main patterns are known, look for any links that might be within data and expand them + //we need to do this before expanding patterns & partials into extendedTemplates, otherwise we could lose the data -> partial reference + pattern_assembler.parse_data_links(patternlab); + //diveSync again to recursively include partials, filling out the //extendedTemplate property of the patternlab.patterns elements diveSync(patterns_dir, { @@ -124,6 +128,7 @@ var patternlab_engine = function () { var allData = JSON.parse(JSON.stringify(patternlab.data)); allData = pattern_assembler.merge_data(allData, pattern.jsonFileData); + //render the extendedTemplate with all data pattern.patternPartial = pattern_assembler.renderPattern(pattern.extendedTemplate, allData); //add footer info before writing diff --git a/builder/patternlab_grunt.js b/builder/patternlab_grunt.js index 606127614..f56e58074 100644 --- a/builder/patternlab_grunt.js +++ b/builder/patternlab_grunt.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab_gulp.js b/builder/patternlab_gulp.js index 5db996f66..e20e1e1a7 100644 --- a/builder/patternlab_gulp.js +++ b/builder/patternlab_gulp.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/pseudopattern_hunter.js b/builder/pseudopattern_hunter.js index b4e69867e..0969c7ac1 100644 --- a/builder/pseudopattern_hunter.js +++ b/builder/pseudopattern_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/style_modifier_hunter.js b/builder/style_modifier_hunter.js index c38ada4fd..8a42889bd 100644 --- a/builder/style_modifier_hunter.js +++ b/builder/style_modifier_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.16.0 - 2015 + * patternlab-node - v1.0.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/package.gulp.json b/package.gulp.json index 313d4edf1..dbece6e4b 100644 --- a/package.gulp.json +++ b/package.gulp.json @@ -1,7 +1,7 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.16.0", + "version": "1.0.0", "devDependencies": { "browser-sync": "^2.10.0", "del": "^2.0.2", diff --git a/package.json b/package.json index 516481505..157d4cc66 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "patternlab-node", "description": "Pattern Lab is a collection of tools to help you create atomic design systems. This is the node command line interface (CLI).", - "version": "0.16.0", + "version": "1.0.0", "devDependencies": { "bs-html-injector": "^3.0.0", "diveSync": "^0.3.0", diff --git a/test/files/_patterns/00-test/link.mustache b/test/files/_patterns/00-test/link.mustache new file mode 100644 index 000000000..b34269824 --- /dev/null +++ b/test/files/_patterns/00-test/link.mustache @@ -0,0 +1 @@ +Cool Dude diff --git a/test/files/_patterns/00-test/nav.json b/test/files/_patterns/00-test/nav.json new file mode 100644 index 000000000..32a6c0952 --- /dev/null +++ b/test/files/_patterns/00-test/nav.json @@ -0,0 +1,11 @@ +{ + "brad" : { + "url" : "link.twitter-brad" + }, + "dave" : { + "url" : "link.twitter-dave" + }, + "brian" : { + "url" : "link.twitter-brian" + } +} diff --git a/test/files/_patterns/00-test/nav.mustache b/test/files/_patterns/00-test/nav.mustache new file mode 100644 index 000000000..b76f77dfc --- /dev/null +++ b/test/files/_patterns/00-test/nav.mustache @@ -0,0 +1,9 @@ +{{# brad }} + {{> test-link }} +{{/ brad }} +{{# dave }} + {{> test-link }} +{{/ dave }} +{{# brian }} + {{> test-link }} +{{/ brian }} diff --git a/test/pattern_assembler_tests.js b/test/pattern_assembler_tests.js index 2519b87ba..6953e2324 100644 --- a/test/pattern_assembler_tests.js +++ b/test/pattern_assembler_tests.js @@ -514,6 +514,7 @@ var pattern_assembler = new pa(); var patterns_dir = './test/files/_patterns'; var patternlab = {}; + //THIS IS BAD. patternlab.config = fs.readJSONSync('./config.json'); patternlab.config.patterns = {source: patterns_dir}; patternlab.data = fs.readJSONSync('./source/_data/data.json'); @@ -596,6 +597,71 @@ //assert test.equals(pattern.patternState, ""); test.done(); + }, + 'parseDataLinks - replaces found link.* data for their expanded links' : function(test){ + //arrange + var diveSync = require('diveSync'); + var fs = require('fs-extra'); + var pa = require('../builder/pattern_assembler'); + var pattern_assembler = new pa(); + var patterns_dir = './test/files/_patterns/'; + var patternlab = {}; + //THIS IS BAD + patternlab.config = fs.readJSONSync('./config.json'); + patternlab.config.patterns = {source: patterns_dir}; + patternlab.data = fs.readJSONSync('./source/_data/data.json'); + patternlab.listitems = fs.readJSONSync('./source/_data/listitems.json'); + patternlab.header = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/header.html', 'utf8'); + patternlab.footer = fs.readFileSync('./source/_patternlab-files/pattern-header-footer/footer.html', 'utf8'); + patternlab.patterns = []; + patternlab.data.link = {}; + patternlab.partials = {}; + + diveSync(patterns_dir, + { + filter: function(path, dir){ + if(dir){ + var remainingPath = path.replace(patterns_dir, ''); + var isValidPath = remainingPath.indexOf('/_') === -1; + return isValidPath; + } + return true; + } + }, + function(err, file){ + //log any errors + if(err){ + console.log(err); + return; + } + pattern_assembler.process_pattern_iterative(file.substring(2), 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'; + + var pattern; + for(var i = 0; i < patternlab.patterns.length; i++){ + if(patternlab.patterns[i].key === 'test-nav'){ + pattern = patternlab.patterns[i]; + } + } + //assert before + test.equals(pattern.jsonFileData.brad.url, "link.twitter-brad"); + test.equals(pattern.jsonFileData.dave.url, "link.twitter-dave"); + test.equals(pattern.jsonFileData.brian.url, "link.twitter-brian"); + + //act + pattern_assembler.parse_data_links(patternlab); + + //assert after + test.equals(pattern.jsonFileData.brad.url, "https://twitter.com/brad_frost"); + test.equals(pattern.jsonFileData.dave.url, "https://twitter.com/dmolsen"); + test.equals(pattern.jsonFileData.brian.url, "https://twitter.com/bmuenzenmeyer"); + test.done(); } }; }());