diff --git a/CHANGELOG b/CHANGELOG index 47e84b680..85124e76e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,11 @@ THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. + +PL-node-v0.11.0 + - ADD: Ignore pattern directories that start with an underscore. + - ADD: Support for lists with the listItems variable + - FIX: Resolved issue where pattern parameter data bled into global data object + - ADD: Support a fluid viewport + PL-node-v0.10.1 - ADD: Added more unit tests for recently more-modular code - FIX: Lineage was not working for patterns with pattern parameters diff --git a/Gruntfile.js b/Gruntfile.js index cd9112eb3..f0708fab1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -47,6 +47,10 @@ module.exports = function(grunt) { pseudopattern_hunter: { src: './builder/pseudopattern_hunter.js', dest: './builder/pseudopattern_hunter.js' + }, + list_item_hunter: { + src: './builder/list_item_hunter.js', + dest: './builder/list_item_hunter.js' } }, copy: { diff --git a/README.md b/README.md index f2eb63b62..c72b197a6 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,40 @@ Pattern states should be lowercase and use hyphens where spaces are present. } ``` +##### Pattern Export +`config.json` also has two properties that work together to export completed patterns for use in a production environment. Provide an array of keys and an output directory. Pattern Lab doesn't ship with any pattern export keys, but the default directory is `"./pattern_exports/"` created inside the install directory. + +``` +"patternExportKeys": ["molecules-primary-nav", "organisms-header", "organisms-header"], +"patternExportDirectory": "./pattern_exports/" +``` + +Coupled with exported css (much easier to extract with existing tools like [grunt-contrib-copy](https://github.com/gruntjs/grunt-contrib-copy)), pattern export can help to maintain the relevancy of the design system by directly placing partials in a directory of your choosing. + +##### baseurl + +If your instance of Pattern Lab lives in a subdirectory of your server, for instance on github pages (ex: yourusername.github.io/patterns-demo/), then add the baseurl here. The baseurl is everything after the hostname - ie: `patterns-demo` + +``` +"baseurl" : "/patterns-demo" +``` + +Default: blank + +##### excluding patterns + +If you'd like to exclude an individual pattern you can do so by prepending the filename with an underscore, like: `_filename.mustache` + +You can also exclude complete directories by prepending the directory name with an underscore, like: `/_experiment/...` + +##### Verbose Mode +`patternlab.json` is a file created for debugging purposes. Set `debug` to true in `.config.json` to see all the secrets. + +##### Server +Running `grunt serve` will compile the patternlab front end and host it on http://localhost:9001 by default. Page will reload on any saved source code change. + +### Advanced Pattern Library Features + ##### Pattern Parameters Pattern parameters are a simple mechanism for replacing Mustache variables via attributes on a pattern partial tag rather than having to use a pattern-specific json file. They are especially useful when you want to supply distinct values for Mustache variables in a specific pattern partial instance that may be included multiple times in a molecule, template, or page. @@ -157,32 +191,6 @@ This would compile to: As you can see, it's a much easier way of linking patterns to one another. -##### Pattern Export -`config.json` also has two properties that work together to export completed patterns for use in a production environment. Provide an array of keys and an output directory. Pattern Lab doesn't ship with any pattern export keys, but the default directory is `"./pattern_exports/"` created inside the install directory. - -``` -"patternExportKeys": ["molecules-primary-nav", "organisms-header", "organisms-header"], -"patternExportDirectory": "./pattern_exports/" -``` - -Coupled with exported css (much easier to extract with existing tools like [grunt-contrib-copy](https://github.com/gruntjs/grunt-contrib-copy)), pattern export can help to maintain the relevancy of the design system by directly placing partials in a directory of your choosing. - -##### baseurl - -If your instance of Pattern Lab lives in a subdirectory of your server, for instance on github pages (ex: yourusername.github.io/patterns-demo/), then add the baseurl here. The baseurl is everything after the hostname - ie: `patterns-demo` - -``` -"baseurl" : "/patterns-demo" -``` - -Default: blank - -##### Verbose Mode -`patternlab.json` is a file created for debugging purposes. Set `debug` to true in `.config.json` to see all the secrets. - -##### Server -Running `grunt serve` will compile the patternlab front end and host it on http://localhost:9001 by default. Page will reload on any saved source code change. - === The Node version of Pattern Lab is maintained by [@bmuenzenmeyer](https://twitter.com/bmuenzenmeyer) and contributors. Pull requests welcome, but please take a moment to read the [guidelines](https://github.com/pattern-lab/patternlab-node/blob/master/CONTRIBUTING.md). @@ -191,9 +199,11 @@ The Node version of Pattern Lab is maintained by [@bmuenzenmeyer](https://twitte You can find some simple upgrade documenation in it's current home here (unreleased but confirmed to work): [https://github.com/pattern-lab/website/blob/dev/patternlabsite/docs/node/upgrading.md](https://github.com/pattern-lab/website/blob/dev/patternlabsite/docs/node/upgrading.md) -### Forward, To the Specification! +### ROADMAP + +A roadmap exists for Pattern Lab Node. Check it out [here](https://github.com/pattern-lab/patternlab-node/issues/134) -Dave Olsen has published the [specification](https://github.com/pattern-lab/the-spec/blob/draft/SPEC.md) for Pattern Lab ports. Development will be oriented toward compliance with this as the spec and the port mature together. +Dave Olsen has also published the [specification](https://github.com/pattern-lab/the-spec/blob/draft/SPEC.md) for Pattern Lab ports. Development will be oriented toward compliance with this as the spec and the port mature together. ### Is Pattern Lab a Platform or a Build Tool? diff --git a/builder/lineage_hunter.js b/builder/lineage_hunter.js index bb072bf74..47bc9c473 100644 --- a/builder/lineage_hunter.js +++ b/builder/lineage_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.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 new file mode 100644 index 000000000..dd251bda3 --- /dev/null +++ b/builder/list_item_hunter.js @@ -0,0 +1,108 @@ +/* + * patternlab-node - v0.11.0 - 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. + * + */ + +(function () { + "use strict"; + + var list_item_hunter = function(){ + + var extend = require('util')._extend, + pa = require('./pattern_assembler'), + mustache = require('mustache'), + pattern_assembler = new pa(), + items = [ 'zero','one','two','three','four','five','six','seven','eight','nine','ten','eleven','twelve','thirteen','fourteen','fifteen','sixteen','seventeen','eighteen','nineteen','twenty']; + + function processListItemPartials(pattern, patternlab){ + //find any listitem blocks + var matches = pattern_assembler.find_list_items(pattern, patternlab); + if(matches !== null){ + matches.forEach(function(liMatch, index, matches){ + + if(patternlab.config.debug){ + console.log('found listItem of size ' + liMatch + ' inside ' + pattern.key); + } + + //find the boundaries of the block + var loopNumberString = liMatch.split('.')[1].split('}')[0].trim(); + var end = liMatch.replace('#', '/'); + var patternBlock = pattern.template.substring(pattern.template.indexOf(liMatch) + liMatch.length, pattern.template.indexOf(end)).trim(); + + //build arrays that repeat the block, however large we need to + var repeatedBlockTemplate = []; + var repeatedBlockHtml = ''; + for(var i = 0; i < items.indexOf(loopNumberString); i++){ + repeatedBlockTemplate.push(patternBlock); + } + + //check for a local listitems.json file + var listData = JSON.parse(JSON.stringify(patternlab.listitems)); + listData = pattern_assembler.merge_data(listData, pattern.patternSpecificListJson); + + //iterate over each copied block, rendering its contents along with pattenlab.listitems[i] + for(var i = 0; i < repeatedBlockTemplate.length; i++){ + + var thisBlockTemplate = repeatedBlockTemplate[i]; + var thisBlockHTML = ""; + + //combine listItem data with pattern data with global data + var itemData = listData['' + items.indexOf(loopNumberString)]; //this is a property like "2" + var globalData = JSON.parse(JSON.stringify(patternlab.data)); + var localData = JSON.parse(JSON.stringify(pattern.jsonFileData)); + + var allData = pattern_assembler.merge_data(globalData, localData); + allData = pattern_assembler.merge_data(allData, itemData[i]); + allData.link = extend({}, patternlab.data.link); + + //check for partials within the repeated block + var foundPartials = pattern_assembler.find_pattern_partials({ 'template' : thisBlockTemplate }); + + if(foundPartials && foundPartials.length > 0){ + + for(var j = 0; j < foundPartials.length; j++){ + + //get the partial + var partialName = foundPartials[j].match(/([a-z-]+)/ig)[0]; + var partialPattern = pattern_assembler.get_pattern_by_key(partialName, patternlab); + + //replace its reference within the block with the extended template + thisBlockTemplate = thisBlockTemplate.replace(foundPartials[j], partialPattern.extendedTemplate); + } + + //render with data + thisBlockHTML = pattern_assembler.renderPattern(thisBlockTemplate, allData, patternlab.partials); + + } else{ + //just render with mergedData + thisBlockHTML = pattern_assembler.renderPattern(thisBlockTemplate, allData, patternlab.partials); + } + + //add the rendered HTML to our string + repeatedBlockHtml = repeatedBlockHtml + thisBlockHTML; + } + + //replace the block with our generated HTML + var repeatingBlock = pattern.extendedTemplate.substring(pattern.extendedTemplate.indexOf(liMatch), pattern.extendedTemplate.indexOf(end) + end.length); + pattern.extendedTemplate = pattern.extendedTemplate.replace(repeatingBlock, repeatedBlockHtml); + + }); + } + } + + return { + process_list_item_partials: function(pattern, patternlab){ + processListItemPartials(pattern, patternlab); + } + }; + + }; + + module.exports = list_item_hunter; + +}()); diff --git a/builder/media_hunter.js b/builder/media_hunter.js index 3900d81ed..289a78bb9 100644 --- a/builder/media_hunter.js +++ b/builder/media_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.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 f1809b16e..6725abe75 100644 --- a/builder/object_factory.js +++ b/builder/object_factory.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -15,8 +15,7 @@ this.fileName = filename.substring(0, filename.indexOf('.')); this.subdir = subdir; this.name = subdir.replace(/[\/\\]/g, '-') + '-' + this.fileName; //this is the unique name with the subDir - this.data = data || null; - this.jsonFileData = {}; + this.jsonFileData = data || {}; this.patternName = this.fileName.substring(this.fileName.indexOf('-') + 1); //this is the display name for the ui this.patternLink = this.name + '/' + this.name + '.html'; this.patternGroup = this.name.substring(this.name.indexOf('-') + 1, this.name.indexOf('-', 4) + 1 - this.name.indexOf('-') + 1); diff --git a/builder/parameter_hunter.js b/builder/parameter_hunter.js index 0541b211f..089b80055 100644 --- a/builder/parameter_hunter.js +++ b/builder/parameter_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -23,9 +23,10 @@ //find the {{> template-name(*) }} within patterns var matches = pattern.template.match(/{{>([ ]+)?([A-Za-z0-9-]+)(\()(.+)(\))([ ]+)?}}/g); if(matches !== null){ + //compile this partial immeadiately, essentially consuming it. matches.forEach(function(pMatch, index, matches){ //find the partial's name - var partialName = pMatch.match(/([a-z-]+)/ig)[0] + var partialName = pMatch.match(/([a-z-]+)/ig)[0]; if(patternlab.config.debug){ console.log('found patternParameters for ' + partialName); @@ -39,20 +40,17 @@ //do no evil. there is no good way to do this that I can think of without using a split, which then makes commas and colons special characters and unusable within the pattern params var paramData = eval(paramString); - //compile this partial immeadiately, essentially consuming it. var partialPattern = pattern_assembler.get_pattern_by_key(partialName, patternlab); - var existingData = pattern.data || patternlab.data; + var globalData = JSON.parse(JSON.stringify(patternlab.data)); + var localData = JSON.parse(JSON.stringify(pattern.jsonFileData)); - //merge paramData with any other data that exists. - for (var prop in paramData) { - if (existingData.hasOwnProperty(prop)) { - existingData[prop] = paramData[prop]; - } - } + var allData = pattern_assembler.merge_data(globalData, localData); + allData = pattern_assembler.merge_data(allData, paramData); //extend pattern data links into link for pattern link shortcuts to work. we do this locally and globally - existingData.link = extend({}, patternlab.data.link); - var renderedPartial = pattern_assembler.renderPattern(partialPattern.extendedTemplate, existingData, patternlab.partials); + allData.link = extend({}, patternlab.data.link); + + var renderedPartial = pattern_assembler.renderPattern(partialPattern.extendedTemplate, allData, patternlab.partials); //remove the parameter from the partial and replace it with the rendered partial + paramData pattern.extendedTemplate = pattern.extendedTemplate.replace(pMatch, renderedPartial); diff --git a/builder/pattern_assembler.js b/builder/pattern_assembler.js index a024a7dac..98b661783 100644 --- a/builder/pattern_assembler.js +++ b/builder/pattern_assembler.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -13,12 +13,27 @@ var pattern_assembler = function(){ + function isObjectEmpty(obj) { + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) + return false; + } + + return true; + } + + //find and return any {{> template-name }} within pattern function findPartials(pattern){ var matches = pattern.template.match(/{{>([ ])?([A-Za-z0-9-]+)(?:\:[A-Za-z0-9-]+)?(?:(| )\(.*)?([ ])?}}/g); return matches; } + function findListItems(pattern){ + var matches = pattern.template.match(/({{#( )?)(listItems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g); + return matches; + } + function setState(pattern, patternlab){ if(patternlab.config.patternStates[pattern.patternName]){ pattern.patternState = patternlab.config.patternStates[pattern.patternName]; @@ -50,7 +65,7 @@ //extract some information var abspath = file.substring(2); - var subdir = path.dirname(path.relative('./source/_patterns', file)).replace('\\', '/'); + var subdir = path.dirname(path.relative(patternlab.config.patterns.source, file)).replace('\\', '/'); var filename = path.basename(file); //ignore _underscored patterns, json (for now), and dotfiles @@ -66,12 +81,22 @@ //look for a json file for this template try { - var jsonFilename = abspath.substr(0, abspath.lastIndexOf(".")) + ".json"; - currentPattern.jsonFileData = fs.readJSONSync(jsonFilename); + var jsonFilename = patternlab.config.patterns.source + currentPattern.subdir + '/' + currentPattern.fileName + ".json"; + currentPattern.jsonFileData = fs.readJSONSync(jsonFilename.substring(2)); + console.log('found pattern-specific data.json for ' + currentPattern.key); } catch(e) { } + //look for a listitems.json file for this template + try { + var listJsonFileName = patternlab.config.patterns.source + currentPattern.subdir + '/' + currentPattern.fileName + ".listitems.json"; + currentPattern.patternSpecificListJson = fs.readJSONSync(listJsonFileName.substring(2)); + console.log('found pattern-specific listitems.json for ' + currentPattern.key); + } + catch(e) { + } + //add the raw template to memory currentPattern.template = fs.readFileSync(abspath, 'utf8'); @@ -86,10 +111,12 @@ lh = require('./lineage_hunter'), ph = require('./parameter_hunter'), pph = require('./pseudopattern_hunter'), + lih = require('./list_item_hunter'), path = require('path'); var parameter_hunter = new ph(), lineage_hunter = new lh(), + list_item_hunter = new lih(), pseudopattern_hunter = new pph(); currentPattern.extendedTemplate = currentPattern.template; @@ -102,6 +129,10 @@ if(patternlab.config.debug){ console.log('found partials for ' + currentPattern.key); } + + //find any listItem partials + list_item_hunter.process_list_item_partials(currentPattern, patternlab); + //determine if the template contains any pattern parameters. if so they must be immediately consumed parameter_hunter.find_parameters(currentPattern, patternlab); @@ -156,10 +187,43 @@ return obj1; } + function buildListItems(patternlab){ + //combine all list items into one structure + var list = []; + for (var item in patternlab.listitems) { + if( patternlab.listitems.hasOwnProperty(item)) { + list.push(patternlab.listitems[item]); + } + } + patternlab.listItemArray = shuffle(list); + + for(var i = 1; i <= patternlab.listItemArray.length; i++){ + var tempItems = []; + if( i === 1){ + tempItems.push(patternlab.listItemArray[0]); + patternlab.listitems['' + i ] = tempItems; + } else{ + for(var c = 1; c <= i; c++){ + tempItems.push(patternlab.listItemArray[c - 1]); + patternlab.listitems['' + i ] = tempItems; + } + } + } + } + + //http://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array-in-javascript + function shuffle(o){ + for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); + return o; + } + return { find_pattern_partials: function(pattern){ return findPartials(pattern); }, + find_list_items: function(pattern){ + return findListItems(pattern) + }, setPatternState: function(pattern, patternlab){ setState(pattern, patternlab); }, @@ -180,6 +244,12 @@ }, merge_data: function(existingData, newData){ return mergeData(existingData, newData); + }, + combine_listItems: function(patternlab){ + buildListItems(patternlab); + }, + is_object_empty: function(obj){ + return isObjectEmpty(obj); } }; diff --git a/builder/pattern_exporter.js b/builder/pattern_exporter.js index 61f62cccf..78560b631 100644 --- a/builder/pattern_exporter.js +++ b/builder/pattern_exporter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/builder/patternlab.js b/builder/patternlab.js index 74e4c186f..d819cff43 100644 --- a/builder/patternlab.js +++ b/builder/patternlab.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. @@ -65,24 +65,35 @@ var patternlab_engine = function () { var pattern_assembler = new pa(), entity_encoder = new he(), - pattern_exporter = new pe(); + pattern_exporter = new pe(), + patterns_dir = './source/_patterns'; - diveSync('./source/_patterns', function(err, file){ - //log any errors - if(err){ - console.log(err); - return; - } + pattern_assembler.combine_listItems(patternlab); - pattern_assembler.process_pattern_file(file, patternlab); + 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_file(file, patternlab); }); //render all patterns last, so lineageR works patternlab.patterns.forEach(function(pattern, index, patterns){ //render the pattern, but first consolidate any data we may have var allData = JSON.parse(JSON.stringify(patternlab.data)); allData = pattern_assembler.merge_data(allData, pattern.jsonFileData); - allData = pattern_assembler.merge_data(allData, pattern.data); pattern.patternPartial = pattern_assembler.renderPattern(pattern.extendedTemplate, allData); diff --git a/builder/patternlab_grunt.js b/builder/patternlab_grunt.js index a79854e6f..72fccc8ff 100644 --- a/builder/patternlab_grunt.js +++ b/builder/patternlab_grunt.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.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 b2b74a125..b5513e458 100644 --- a/builder/pseudopattern_hunter.js +++ b/builder/pseudopattern_hunter.js @@ -1,5 +1,5 @@ /* - * patternlab-node - v0.10.1 - 2015 + * patternlab-node - v0.11.0 - 2015 * * Brian Muenzenmeyer, and the web community. * Licensed under the MIT license. diff --git a/package.json b/package.json index 91df44efb..8e0a247ad 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.10.1", + "version": "0.11.0", "devDependencies": { "grunt": "~0.4.0", "grunt-contrib-watch": "^0.6.1", diff --git a/public/styleguide/js/styleguide.js b/public/styleguide/js/styleguide.js index 8c9616255..05d7cb276 100644 --- a/public/styleguide/js/styleguide.js +++ b/public/styleguide/js/styleguide.js @@ -1,5 +1,5 @@ (function(w){ - + var sw = document.body.clientWidth, //Viewport Width sh = $(document).height(), //Viewport Height minViewportWidth = 240, //Minimum Size for Viewport @@ -12,14 +12,19 @@ $headerHeight = $('.sg-header').height(), discoID = false, discoMode = false, + fullMode = true, hayMode = false; - - + $(w).resize(function(){ //Update dimensions on resize sw = document.body.clientWidth; sh = $(document).height(); setAccordionHeight(); + + if(fullMode === true) { + sizeiframe(sw, false); + }; + }); /* Pattern Lab accordion dropdown */ @@ -43,12 +48,12 @@ setAccordionHeight(); }); - //Accordion Height + //Accordion Height function setAccordionHeight() { var $activeAccordion = $('.sg-acc-panel.active').first(), accordionHeight = $activeAccordion.height(), availableHeight = sh-$headerHeight; //Screen height minus the height of the header - + $activeAccordion.height(availableHeight); //Set height of accordion to the available height } @@ -56,7 +61,7 @@ e.preventDefault(); $('.sg-nav-container').toggleClass('active'); }); - + //"View (containing clean, code, raw, etc options) Trigger $('#sg-t-toggle').on("click", function(e){ e.preventDefault(); @@ -68,84 +73,89 @@ e.preventDefault(); $(this).parents('ul').toggleClass('active'); }); - + //Phase View Events $('.sg-size[data-size]').on("click", function(e){ e.preventDefault(); killDisco(); killHay(); - + fullMode = false; + var val = $(this).attr('data-size'); - + if (val.indexOf('px') > -1) { $bodySize = 1; } - - val = val.replace(/[^\d.-]/g,'') + + val = val.replace(/[^\d.-]/g,'') sizeiframe(Math.floor(val*$bodySize)); }); - + //Size View Events // handle small button function goSmall() { killDisco(); killHay(); + fullMode = false; sizeiframe(getRandom(minViewportWidth,500)); } - + $('#sg-size-s').on("click", function(e){ e.preventDefault(); goSmall(); }); - + jwerty.key('ctrl+shift+s', function(e) { goSmall(); return false; }); - + // handle medium button function goMedium() { killDisco(); killHay(); + fullMode = false; sizeiframe(getRandom(500,800)); } - + $('#sg-size-m').on("click", function(e){ e.preventDefault(); goMedium(); }); - + jwerty.key('ctrl+shift+m', function(e) { goMedium(); return false; }); - + // handle large button function goLarge() { killDisco(); killHay(); + fullMode = false; sizeiframe(getRandom(800,1200)); } - + $('#sg-size-l').on("click", function(e){ e.preventDefault(); goLarge(); }); - + jwerty.key('ctrl+shift+l', function(e) { goLarge(); return false; }); //Click Full Width Button - $('#sg-size-full').on("click", function(e){ //Resets + $('#sg-size-full').on("click", function(e){ //Resets e.preventDefault(); killDisco(); killHay(); + fullMode = true; sizeiframe(sw); }); - + //Click Random Size Button $('#sg-size-random').on("click", function(e){ e.preventDefault(); @@ -153,11 +163,12 @@ killHay(); sizeiframe(getRandom(minViewportWidth,sw)); }); - + //Click for Disco Mode, which resizes the viewport randomly $('#sg-size-disco').on("click", function(e){ e.preventDefault(); killHay(); + fullMode = false; if (discoMode) { killDisco(); @@ -171,19 +182,19 @@ function disco() { sizeiframe(getRandom(minViewportWidth,sw)); } - + function killDisco() { discoMode = false; clearInterval(discoID); discoID = false; } - + function startDisco() { killHay(); discoMode = true; discoID = setInterval(disco, 800); } - + jwerty.key('ctrl+shift+d', function(e) { if (!discoMode) { startDisco(); @@ -212,22 +223,22 @@ $('#sg-gen-container').removeClass('hay-mode'); sizeiframe(Math.floor(currentWidth)); } - + // start Hay! mode function startHay() { killDisco(); hayMode = true; $('#sg-gen-container').removeClass("vp-animate").width(minViewportWidth+viewportResizeHandleWidth); $sgViewport.removeClass("vp-animate").width(minViewportWidth); - + var timeoutID = window.setTimeout(function(){ $('#sg-gen-container').addClass('hay-mode').width(maxViewportWidth+viewportResizeHandleWidth); $sgViewport.addClass('hay-mode').width(maxViewportWidth); - + setInterval(function(){ var vpSize = $sgViewport.width(); updateSizeReading(vpSize); },100); }, 200); } - + // start hay from a keyboard shortcut jwerty.key('ctrl+shift+h', function(e) { if (hayMode) { @@ -280,20 +291,20 @@ var val = parseFloat($(this).val()); updateSizeReading(val,'em','updatePxInput'); }); - + // set 0 to 320px as a default jwerty.key('ctrl+shift+0', function(e) { e.preventDefault(); sizeiframe(320,true); return false; }); - + // handle the MQ click var mqs = []; $('#sg-mq a').each(function(i) { - + mqs.push($(this).html()); - + // bind the click $(this).on("click", function(i,k) { return function(e) { @@ -305,7 +316,7 @@ sizeiframe(width,true); } }(i,this)); - + // bind the keyboard shortcut. can't use cmd on a mac because 3 & 4 are for screenshots jwerty.key('ctrl+shift+'+(i+1), function (k) { return function(e) { @@ -317,9 +328,9 @@ return false; } }(this)); - + }); - + //Resize the viewport //'size' is the target size of the viewport //'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging @@ -335,7 +346,7 @@ } //Conditionally remove CSS animation class from viewport - if(animate==false) { + if(animate==false) { $('#sg-gen-container,#sg-viewport').removeClass("vp-animate"); //If aninate is set to false, remove animate class from viewport } else { $('#sg-gen-container,#sg-viewport').addClass("vp-animate"); @@ -347,7 +358,7 @@ updateSizeReading(theSize); //Update values in toolbar saveSize(theSize); //Save current viewport to cookie } - + function saveSize(size) { if (!DataSaver.findValue('vpWidth')) { DataSaver.addValue("vpWidth",size); @@ -355,8 +366,8 @@ DataSaver.updateValue("vpWidth",size); } } - - + + //Update Pixel and Em inputs //'size' is the input number //'unit' is the type of unit: either px or em. Default is px. Accepted values are 'px' and 'em' @@ -369,7 +380,7 @@ pxSize = size; emSize = size/$bodySize; } - + if (target == 'updatePxInput') { $sizePx.val(pxSize); } else if (target == 'updateEmInput') { @@ -377,19 +388,19 @@ } else { $sizeEms.val(emSize.toFixed(2)); $sizePx.val(pxSize); - } + } } - + /* Returns a random number between min and max */ function getRandom (min, max) { return Math.random() * (max - min) + min; } - + function updateViewportWidth(size) { - + $("#sg-viewport").width(size); $("#sg-gen-container").width(size*1 + 14); - + updateSizeReading(size); } @@ -398,27 +409,29 @@ // 2. make a hidden div visible so that it can track mouse movements and make sure the pointer doesn't get lost in the iframe // 3. on "mousemove" calculate the math, save the results to a cookie, and update the viewport $('#sg-rightpull').mousedown(function(event) { - + // capture default data var origClientX = event.clientX; var origViewportWidth = $sgViewport.width(); - + + fullMode = false; + // show the cover $("#sg-cover").css("display","block"); - + // add the mouse move event and capture data. also update the viewport width $('#sg-cover').mousemove(function(event) { - + viewportWidth = (origClientX > event.clientX) ? origViewportWidth - ((origClientX - event.clientX)*2) : origViewportWidth + ((event.clientX - origClientX)*2); - + if (viewportWidth > minViewportWidth) { - + if (!DataSaver.findValue('vpWidth')) { DataSaver.addValue("vpWidth",viewportWidth); } else { DataSaver.updateValue("vpWidth",viewportWidth); } - + sizeiframe(viewportWidth,false); } }); @@ -438,7 +451,7 @@ // get the request vars var oGetVars = urlHandler.getRequestVars(); - + // pre-load the viewport width var vpWidth = 0; var trackViewportWidth = true; // can toggle this feature on & off @@ -454,7 +467,7 @@ } else if (trackViewportWidth && (vpWidth = DataSaver.findValue("vpWidth"))) { updateViewportWidth(vpWidth); } - + // load the iframe source var patternName = "all"; var patternPath = ""; @@ -464,36 +477,36 @@ patternPath = urlHandler.getFileName(patternName); iFramePath = (patternPath != "") ? window.location.protocol+"//"+window.location.host+window.location.pathname.replace("index.html","")+patternPath : iFramePath; } - + if (patternName != "all") { document.getElementById("title").innerHTML = "Pattern Lab - "+patternName; history.replaceState({ "pattern": patternName }, null, null); } - + document.getElementById("sg-raw").setAttribute("href",urlHandler.getFileName(patternName)); - + urlHandler.skipBack = true; document.getElementById("sg-viewport").contentWindow.location.replace(iFramePath); - + //IFrame functionality - + // update the iframe with the source from clicked element in pull down menu. also close the menu // having it outside fixes an auto-close bug i ran into $('.sg-nav a').not('.sg-acc-handle').on("click", function(e){ - + e.preventDefault(); - + // update the iframe via the history api handler document.getElementById("sg-viewport").contentWindow.postMessage( { "path": urlHandler.getFileName($(this).attr("data-patternpartial")) }, urlHandler.targetOrigin); - + // close up the menu $(this).parents('.sg-acc-panel').toggleClass('active'); $(this).parents('.sg-acc-panel').siblings('.sg-acc-handle').toggleClass('active'); - + return false; - + }); // handle when someone clicks on the grey area of the viewport so it auto-closes the nav @@ -504,7 +517,7 @@ function closePanels() { $(this).toggleClass('active'); } }); - + $('.sg-acc-handle').each(function() { if ($(this).hasClass('active')) { $(this).toggleClass('active'); @@ -513,43 +526,43 @@ function closePanels() { } $('#sg-vp-wrap').click(function(e) { - + closePanels(); - + }); // watch the iframe source so that it can be sent back to everyone else. // based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage function receiveIframeMessage(event) { - + var data = (typeof event.data !== "string") ? event.data : JSON.parse(event.data); - + // 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; } - + if (data.bodyclick !== undefined) { - + closePanels(); - + } else if (data.patternpartial !== undefined) { - + if (!urlHandler.skipBack) { - + if ((history.state === undefined) || (history.state === null) || (history.state.pattern !== data.patternpartial)) { urlHandler.pushPattern(data.patternpartial, data.path); } - + if (wsnConnected) { var iFramePath = urlHandler.getFileName(data.patternpartial); wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+event.data.patternpartial+'" }' ); } } - + // reset the defaults urlHandler.skipBack = false; - + } else if (data.keyPress !== undefined) { if (data.keyPress == 'ctrl+shift+s') { goSmall(); @@ -571,7 +584,7 @@ function receiveIframeMessage(event) { } } else if (data.keyPress == 'ctrl+shift+0') { sizeiframe(320,true); - } else if (found = data.keyPress.match(/ctrl\+shift\+([1-9])/)) { + } else if (found == data.keyPress.match(/ctrl\+shift\+([1-9])/)) { var val = mqs[(found[1]-1)]; var type = (val.indexOf("px") !== -1) ? "px" : "em"; val = val.replace(type,""); diff --git a/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache b/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache index a6a48dc66..6e150a137 100644 --- a/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache +++ b/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache @@ -3,9 +3,9 @@

59 Comments

{{> molecules-comment-form }} {{> molecules-pagination }} diff --git a/test/list_item_hunter_tests.js b/test/list_item_hunter_tests.js new file mode 100644 index 000000000..0da3c9288 --- /dev/null +++ b/test/list_item_hunter_tests.js @@ -0,0 +1,167 @@ +(function () { + "use strict"; + + var lih = require('../builder/list_item_hunter'); + + exports['list_item_hunter'] = { + 'process_list_item_partials finds and outputs basic repeating blocks' : function(test){ + //arrange + //setup current pattern from what we would have during execution + var currentPattern = { + "template": "{{#listItems.two}}{{ title }}{{/listItems.two}}", + "extendedTemplate" : "{{#listItems.two}}{{ title }}{{/listItems.two}}", + "key": "test-patternName", + "jsonFileData" : {} + }; + + var patternlab = { + "listitems": { + "1": [ + { + "title": "Foo" + } + ], + "2": [ + { + "title": "Foo" + }, + { + "title": "Bar" + } + ] + }, + "data": { + "link": {}, + "partials": [] + }, + "config": {"debug": false} + }; + + var list_item_hunter = new lih(); + + //act + list_item_hunter.process_list_item_partials(currentPattern, patternlab); + + //assert + test.equals(currentPattern.extendedTemplate, "FooBar" ); + + test.done(); + }, + + 'process_list_item_partials finds partials and outputs repeated renders' : function(test){ + //arrange + //setup current pattern from what we would have during execution + var currentPattern = { + "template": "{{#listItems.two}}{{ title }}{{/listItems.two}}", + "extendedTemplate" : "{{#listItems.two}}{{> test-simple }}{{/listItems.two}}", + "key": "test-patternName", + "jsonFileData" : {} + }; + + var patternlab = { + "listitems": { + "1": [ + { + "title": "Foo" + } + ], + "2": [ + { + "title": "Foo" + }, + { + "title": "Bar" + } + ] + }, + "data": { + "link": {}, + "partials": [] + }, + "config": {"debug": false}, + "patterns": [ + { + "template": "{{ title }}", + "extendedTemplate" : "{{ title }}", + "key": "test-simple", + "jsonFileData" : {} + } + ] + }; + + var list_item_hunter = new lih(); + + //act + list_item_hunter.process_list_item_partials(currentPattern, patternlab); + + //assert + test.equals(currentPattern.extendedTemplate, "FooBar" ); + + test.done(); + }, + + 'process_list_item_partials overwrites listItem data if local .listitem.json is found' : function(test){ + //arrange + //setup current pattern from what we would have during execution + var currentPattern = { + "template": "{{#listItems.two}}{{ title }}{{/listItems.two}}", + "extendedTemplate" : "{{#listItems.two}}{{> test-simple }}{{/listItems.two}}", + "key": "test-patternName", + "jsonFileData" : {}, + "patternSpecificListJson" : { + "2": [ + { + "title": "One" + }, + { + "title": "Two" + }, + ] + } + }; + + var patternlab = { + "listitems": { + "1": [ + { + "title": "Foo" + } + ], + "2": [ + { + "title": "Foo" + }, + { + "title": "Bar" + } + ] + }, + "data": { + "link": {}, + "partials": [] + }, + "config": {"debug": false}, + "patterns": [ + { + "template": "{{ title }}", + "extendedTemplate" : "{{ title }}", + "key": "test-simple", + "jsonFileData" : {} + } + ] + }; + + var list_item_hunter = new lih(); + + //act + list_item_hunter.process_list_item_partials(currentPattern, patternlab); + + //assert + test.equals(currentPattern.extendedTemplate, "OneTwo" ); + + test.done(); + } + + }; + +}()); diff --git a/test/object_factory_tests.js b/test/object_factory_tests.js index 9bffad0ab..63ca0cc7f 100644 --- a/test/object_factory_tests.js +++ b/test/object_factory_tests.js @@ -9,7 +9,7 @@ test.equals(p.name, '00-atoms-00-global-00-colors'); test.equals(p.subdir, '00-atoms/00-global'); test.equals(p.fileName, '00-colors'); - test.equals(p.data.d, 123); + test.equals(p.jsonFileData.d, 123); test.equals(p.patternName, 'colors'); test.equals(p.patternLink, '00-atoms-00-global-00-colors/00-atoms-00-global-00-colors.html'); test.equals(p.patternGroup, 'atoms');