mirror of
https://github.com/pattern-lab/patternlab-php.git
synced 2025-05-05 21:15:24 +02:00
1365 lines
50 KiB
PHP
1365 lines
50 KiB
PHP
<?php
|
|
|
|
/*!
|
|
* Pattern Lab Builder Class - v0.7.11
|
|
*
|
|
* Copyright (c) 2013-2014 Dave Olsen, http://dmolsen.com
|
|
* Licensed under the MIT license
|
|
*
|
|
* Does the vast majority of heavy lifting for the Generator and Watch classes
|
|
*
|
|
*/
|
|
|
|
namespace PatternLab;
|
|
|
|
use \Mustache_Engine as Engine;
|
|
use \Mustache_Loader_PatternLoader as PatternLoader;
|
|
use \Mustache_Loader_FilesystemLoader as FilesystemLoader;
|
|
|
|
class Builder {
|
|
|
|
/**
|
|
* When initializing the Builder class or the sub-classes make sure the base properties are configured
|
|
* Also, create the config if it doesn't already exist
|
|
*/
|
|
public function __construct($config = array()) {
|
|
|
|
// making sure the config isn't empty
|
|
if (empty($config)) {
|
|
print "A set of configuration options is required to use Pattern Lab.\n";
|
|
exit;
|
|
}
|
|
|
|
// populate some standard variables out of the config
|
|
foreach ($config as $key => $value) {
|
|
|
|
// if the variables are array-like make sure the properties are validated/trimmed/lowercased before saving
|
|
$arrayKeys = array("ie","id","patternStates","styleGuideExcludes");
|
|
if (in_array($key,$arrayKeys)) {
|
|
$values = explode(",",$value);
|
|
array_walk($values,'PatternLab\Builder::trim');
|
|
$this->$key = $values;
|
|
} else if ($key == "ishControlsHide") {
|
|
$this->$key = new \stdClass();
|
|
if ($value != "") {
|
|
$values = explode(",",$value);
|
|
foreach($values as $value2) {
|
|
$value2 = trim($value2);
|
|
$this->$key->$value2 = true;
|
|
}
|
|
}
|
|
if ($this->pageFollowNav == "false") {
|
|
$value = "tools-follow";
|
|
$this->$key->$value = true;
|
|
}
|
|
if ($this->autoReloadNav == "false") {
|
|
$value = "tools-reload";
|
|
$this->$key->$value = true;
|
|
}
|
|
} else {
|
|
$this->$key = $value;
|
|
}
|
|
|
|
}
|
|
|
|
// set-up the source & public dirs
|
|
$this->sp = "/../../../source/_patterns".DIRECTORY_SEPARATOR;
|
|
$this->pp = "/../../../public/patterns".DIRECTORY_SEPARATOR;
|
|
$this->sd = __DIR__."/../../../source";
|
|
$this->pd = __DIR__."/../../../public";
|
|
|
|
// provide the default for enable CSS. performance hog so it should be run infrequently
|
|
$this->enableCSS = false;
|
|
$this->patternCSS = array();
|
|
|
|
}
|
|
|
|
/**
|
|
* Load a new Mustache instance that uses the Pattern Loader
|
|
*
|
|
* @return {Object} an instance of the Mustache engine
|
|
*/
|
|
protected function loadMustachePatternLoaderInstance() {
|
|
$this->mpl = new Engine(array(
|
|
"loader" => new PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths)),
|
|
"partials_loader" => new PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths))
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Load a new Mustache instance that uses the File System Loader
|
|
*
|
|
* @return {Object} an instance of the Mustache engine
|
|
*/
|
|
protected function loadMustacheFileSystemLoaderInstance() {
|
|
$this->mfs = new Engine(array(
|
|
"loader" => new FilesystemLoader(__DIR__."/../../templates/"),
|
|
"partials_loader" => new FilesystemLoader(__DIR__."/../../templates/partials/")
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Load a new Mustache instance that uses the File System Loader
|
|
*
|
|
* @return {Object} an instance of the Mustache engine
|
|
*/
|
|
protected function loadMustacheVanillaInstance() {
|
|
$this->mv = new Engine;
|
|
}
|
|
|
|
/**
|
|
* Renders a given pattern file using Mustache and incorporating the provided data
|
|
* @param {String} the filename of the file to be rendered
|
|
* @param {String} the pattern partial
|
|
*
|
|
* @return {String} the mark-up as rendered by Mustache
|
|
*/
|
|
protected function renderPattern($f,$p) {
|
|
|
|
// if there is pattern-specific data make sure to override the default in $this->d
|
|
$d = $this->d;
|
|
|
|
if (isset($d["patternSpecific"]) && array_key_exists($p,$d["patternSpecific"])) {
|
|
|
|
if (!empty($d["patternSpecific"][$p]["data"])) {
|
|
$d = array_replace_recursive($d, $d["patternSpecific"][$p]["data"]);
|
|
}
|
|
|
|
if (!empty($d["patternSpecific"][$p]["listItems"])) {
|
|
|
|
$numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve");
|
|
|
|
$k = 0;
|
|
$c = count($d["patternSpecific"][$p]["listItems"]);
|
|
|
|
while ($k < $c) {
|
|
$section = $numbers[$k];
|
|
$d["listItems"][$section] = array_replace_recursive( $d["listItems"][$section], $d["patternSpecific"][$p]["listItems"][$section]);
|
|
$k++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$pattern = $this->mpl->render($f,$d);
|
|
$escaped = htmlentities($pattern);
|
|
|
|
if ($this->addPatternHF) {
|
|
$patternHead = $this->mv->render($this->patternHead,$d);
|
|
$patternFoot = $this->mv->render($this->patternFoot,$d);
|
|
$pattern = $patternHead.$pattern.$patternFoot;
|
|
}
|
|
|
|
return array($pattern,$escaped);
|
|
|
|
}
|
|
|
|
/**
|
|
* Generates the index page and style guide
|
|
*/
|
|
protected function generateMainPages() {
|
|
|
|
// make sure $this->mfs & $this->mv are refreshed
|
|
$this->loadMustacheFileSystemLoaderInstance();
|
|
$this->loadMustacheVanillaInstance();
|
|
|
|
// get the source pattern paths
|
|
$patternPathDests = array();
|
|
foreach($this->patternPaths as $patternType => $patterns) {
|
|
$patternPathDests[$patternType] = array();
|
|
foreach ($patterns as $pattern => $patternInfo) {
|
|
if ($patternInfo["render"]) {
|
|
$patternPathDests[$patternType][$pattern] = $patternInfo["patternDestPath"];
|
|
}
|
|
}
|
|
}
|
|
|
|
// render out the main pages and move them to public
|
|
$this->navItems['autoreloadnav'] = $this->autoReloadNav;
|
|
$this->navItems['autoreloadport'] = $this->autoReloadPort;
|
|
$this->navItems['pagefollownav'] = $this->pageFollowNav;
|
|
$this->navItems['pagefollowport'] = $this->pageFollowPort;
|
|
$this->navItems['patternpaths'] = json_encode($patternPathDests);
|
|
$this->navItems['viewallpaths'] = json_encode($this->viewAllPaths);
|
|
$this->navItems['mqs'] = $this->gatherMQs();
|
|
$this->navItems['qrcodegeneratoron'] = $this->qrCodeGeneratorOn;
|
|
$this->navItems['ipaddress'] = getHostByName(getHostName());
|
|
$this->navItems['xiphostname'] = $this->xipHostname;
|
|
$this->navItems['ishminimum'] = $this->ishMinimum;
|
|
$this->navItems['ishmaximum'] = $this->ishMaximum;
|
|
$this->navItems['ishControlsHide'] = $this->ishControlsHide;
|
|
|
|
// grab the partials into a data object for the style guide
|
|
$sd = array("partials" => array());
|
|
foreach ($this->patternPartials as $patternSubtypes) {
|
|
foreach ($patternSubtypes as $patterns) {
|
|
$sd["partials"][] = $patterns;
|
|
}
|
|
}
|
|
|
|
// render the "view all" pages
|
|
$this->generateViewAllPages();
|
|
|
|
// add cacheBuster info
|
|
$this->navItems['cacheBuster'] = $this->cacheBuster;
|
|
$sd['cacheBuster'] = $this->cacheBuster;
|
|
|
|
// render the index page
|
|
$r = $this->mfs->render('index',$this->navItems);
|
|
file_put_contents($this->pd."/index.html",$r);
|
|
|
|
// render the style guide
|
|
$sd = array_replace_recursive($this->d,$sd);
|
|
$styleGuideHead = $this->mv->render($this->mainPageHead,$sd);
|
|
$styleGuideFoot = $this->mv->render($this->mainPageFoot,$sd);
|
|
$styleGuidePage = $styleGuideHead.$this->mfs->render('viewall',$sd).$styleGuideFoot;
|
|
|
|
if (!file_exists($this->pd."/styleguide/html/styleguide.html")) {
|
|
print "ERROR: the main style guide wasn't written out. make sure public/styleguide exists. can copy core/styleguide\n";
|
|
} else {
|
|
file_put_contents($this->pd."/styleguide/html/styleguide.html",$styleGuidePage);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Generates all of the patterns and puts them in the public directory
|
|
*/
|
|
protected function generatePatterns() {
|
|
|
|
// make sure patterns exists
|
|
if (!is_dir($this->pd."/patterns")) {
|
|
mkdir($this->pd."/patterns");
|
|
}
|
|
|
|
// make sure the pattern header & footer are added
|
|
$this->addPatternHF = true;
|
|
|
|
// make sure $this->mpl & $this->mv are refreshed
|
|
$this->loadMustachePatternLoaderInstance();
|
|
$this->loadMustacheVanillaInstance();
|
|
|
|
// loop over the pattern paths to generate patterns for each
|
|
foreach($this->patternPaths as $patternType) {
|
|
|
|
foreach($patternType as $pattern => $pathInfo) {
|
|
|
|
// make sure this pattern should be rendered
|
|
if ($pathInfo["render"]) {
|
|
|
|
// get the rendered, escaped, and mustache pattern
|
|
$this->generatePatternFile($pathInfo["patternSrcPath"].".mustache",$pathInfo["patternPartial"],$pathInfo["patternDestPath"],$pathInfo["patternState"]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Generates a pattern with a header & footer, the escaped version of a pattern, the msutache template, and the css if appropriate
|
|
* @param {String} the filename of the file to be rendered
|
|
* @param {String} the pattern partial
|
|
* @param {String} path where the files need to be written too
|
|
* @param {String} pattern state
|
|
*/
|
|
private function generatePatternFile($f,$p,$path,$state) {
|
|
|
|
// render the pattern and return it as well as the encoded version
|
|
list($rf,$e) = $this->renderPattern($f,$p);
|
|
|
|
// the core footer isn't rendered as mustache but we have some variables there any way. find & replace.
|
|
$rf = str_replace("{% patternPartial %}",$p,$rf);
|
|
$rf = str_replace("{% lineage %}",json_encode($this->patternLineages[$p]),$rf);
|
|
$rf = str_replace("{% lineageR %}",json_encode($this->patternLineagesR[$p]),$rf);
|
|
$rf = str_replace("{% patternState %}",$state,$rf);
|
|
|
|
// figure out what to put in the css section
|
|
$c = $this->enableCSS && isset($this->patternCSS[$p]) ? "true" : "false";
|
|
$rf = str_replace("{% cssEnabled %}",$c,$rf);
|
|
|
|
// get the original mustache template
|
|
$m = htmlentities(file_get_contents(__DIR__.$this->sp.$f));
|
|
|
|
// if the pattern directory doesn't exist create it
|
|
if (!is_dir(__DIR__.$this->pp.$path)) {
|
|
mkdir(__DIR__.$this->pp.$path);
|
|
}
|
|
|
|
// write out the various pattern files
|
|
file_put_contents(__DIR__.$this->pp.$path."/".$path.".html",$rf);
|
|
file_put_contents(__DIR__.$this->pp.$path."/".$path.".escaped.html",$e);
|
|
file_put_contents(__DIR__.$this->pp.$path."/".$path.".mustache",$m);
|
|
if ($this->enableCSS && isset($this->patternCSS[$p])) {
|
|
file_put_contents(__DIR__.$this->pp.$path."/".$path.".css",htmlentities($this->patternCSS[$p]));
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Generates the view all pages
|
|
*/
|
|
protected function generateViewAllPages() {
|
|
|
|
// make sure $this->mfs & $this->mv are refreshed on each generation of view all
|
|
$this->loadMustacheFileSystemLoaderInstance();
|
|
$this->loadMustacheVanillaInstance();
|
|
|
|
// add view all to each list
|
|
$i = 0; $k = 0;
|
|
foreach ($this->navItems['patternTypes'] as $bucket) {
|
|
|
|
// make sure that the navItems index exists. catches issues with pages & templates
|
|
if (isset($bucket["patternTypeItems"])) {
|
|
|
|
foreach ($bucket["patternTypeItems"] as $navItem) {
|
|
|
|
// make sure the navSubItems index exists. catches issues with empty folders
|
|
if (isset($navItem["patternSubtypeItems"])) {
|
|
|
|
foreach ($navItem["patternSubtypeItems"] as $subItem) {
|
|
|
|
if ($subItem["patternName"] == "View All") {
|
|
|
|
// get the pattern parts
|
|
$patternType = $subItem["patternType"];
|
|
$patternSubType = $subItem["patternSubtype"];
|
|
|
|
// get all the rendered partials that match
|
|
$sid = array("partials" => $this->patternPartials[$this->getPatternName($patternType,false)."-".$this->getPatternName($patternSubType,false)]);
|
|
$sid["patternPartial"] = $subItem["patternPartial"];
|
|
$sid["cacheBuster"] = $this->cacheBuster;
|
|
$sid = array_replace_recursive($this->d,$sid);
|
|
|
|
// render the viewall template
|
|
$viewAllHead = $this->mv->render($this->mainPageHead,$sid);
|
|
$viewAllFoot = $this->mv->render($this->mainPageFoot,$sid);
|
|
$viewAllPage = $viewAllHead.$this->mfs->render('viewall',$sid).$viewAllFoot;
|
|
|
|
// if the pattern directory doesn't exist create it
|
|
$patternPath = $patternType."-".$patternSubType;
|
|
if (!is_dir(__DIR__.$this->pp.$patternPath)) {
|
|
mkdir(__DIR__.$this->pp.$patternPath);
|
|
file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$viewAllPage);
|
|
} else {
|
|
file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$viewAllPage);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$i++;
|
|
$k = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Gather data from source/_data/_data.json, source/_data/_listitems.json, and pattern-specific json files
|
|
*
|
|
* Reserved attributes:
|
|
* - $this->d["listItems"] : listItems from listitems.json, duplicated into separate arrays for $this->d->listItems->one, $this->d->listItems->two, $this->d->listItems->three... etc.
|
|
* - $this->d["link"] : the links to each pattern
|
|
* - $this->d["cacheBuster"] : the cache buster value to be appended to URLs
|
|
* - $this->d["patternSpecific"] : holds attributes from the pattern-specific data files
|
|
*
|
|
* @return {Array} populates $this->d
|
|
*/
|
|
protected function gatherData() {
|
|
|
|
// set the cacheBuster
|
|
$this->cacheBuster = ($this->noCacheBuster || ($this->cacheBusterOn == "false")) ? 0 : time();
|
|
|
|
// gather the data from the main source data.json
|
|
if (file_exists($this->sd."/_data/_data.json")) {
|
|
$this->d = json_decode(file_get_contents($this->sd."/_data/_data.json"),true);
|
|
$this->jsonLastErrorMsg("_data/_data.json");
|
|
} else {
|
|
print "Missing a required file, source/_data/_data.json. Aborting.\n";
|
|
exit;
|
|
}
|
|
|
|
$reservedKeys = array("listItems","cacheBuster","link","patternSpecific");
|
|
foreach ($reservedKeys as $reservedKey) {
|
|
if (array_key_exists($reservedKey,$this->d)) {
|
|
print "\"".$reservedKey."\" is a reserved key in Pattern Lab. The data using that key in _data.json will be overwritten. Please choose a new key.\n";
|
|
}
|
|
}
|
|
|
|
|
|
$this->d["listItems"] = $this->getListItems($this->sd."/_data/_listitems.json");
|
|
$this->d["cacheBuster"] = $this->cacheBuster;
|
|
$this->d["link"] = array();
|
|
$this->d["patternSpecific"] = array();
|
|
|
|
}
|
|
|
|
/**
|
|
* Finds the regular and reverse lineages for the patterns
|
|
*
|
|
* @return {Array} an array of patterns with their lineages
|
|
*/
|
|
protected function gatherLineages() {
|
|
|
|
$this->patternLineages = array();
|
|
$this->patternLineagesR = array();
|
|
$foundLineages = array();
|
|
|
|
// check for the regular lineages
|
|
foreach($this->patternPaths as $patternType => $patterns) {
|
|
|
|
foreach ($patterns as $pattern => $patternInfo) {
|
|
|
|
$patternLineage = array();
|
|
$filename = $patternInfo["patternSrcPath"];
|
|
|
|
// if a file doesn't exist it assumes it's a pseudo-pattern and will use the last lineage found
|
|
if (file_exists(__DIR__.$this->sp.$filename.".mustache")) {
|
|
$foundLineages = array_unique($this->getLineage($filename));
|
|
}
|
|
|
|
if (count($foundLineages) > 0) {
|
|
foreach ($foundLineages as $lineage) {
|
|
$patternBits = $this->getPatternInfo($lineage);
|
|
if ((count($patternBits) == 2) && isset($this->patternPaths[$patternBits[0]][$patternBits[1]])) {
|
|
$path = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternDestPath"];
|
|
$patternLineage[] = array("lineagePattern" => $lineage,
|
|
"lineagePath" => "../../patterns/".$path."/".$path.".html");
|
|
} else {
|
|
if (strpos($lineage, '/') === false) {
|
|
print "You may have a typo in ".$patternInfo["patternSrcPath"].". {{> ".$lineage." }} is not a valid pattern.\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->patternLineages[$patternType."-".$pattern] = $patternLineage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// check for the reverse lineages
|
|
foreach ($this->patternLineages as $needlePartial => $needleLineages) {
|
|
|
|
$patternLineageR = array();
|
|
|
|
foreach ($this->patternLineages as $haystackPartial => $haystackLineages) {
|
|
|
|
foreach ($haystackLineages as $haystackLineage) {
|
|
|
|
if ($haystackLineage["lineagePattern"] == $needlePartial) {
|
|
|
|
$foundAlready = false;
|
|
foreach ($patternLineageR as $patternCheck) {
|
|
if ($patternCheck["lineagePattern"] == $haystackPartial) {
|
|
$foundAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$foundAlready) {
|
|
$patternBits = $this->getPatternInfo($haystackPartial);
|
|
if (isset($this->patternPaths[$patternBits[0]][$patternBits[1]])) {
|
|
$path = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternDestPath"];
|
|
$patternLineageR[] = array("lineagePattern" => $haystackPartial,
|
|
"lineagePath" => "../../patterns/".$path."/".$path.".html");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$this->patternLineagesR[$needlePartial] = $patternLineageR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Finds Media Queries in CSS files in the source/css/ dir
|
|
*
|
|
* @return {Array} an array of the appropriate MQs
|
|
*/
|
|
protected function gatherMQs() {
|
|
|
|
$mqs = array();
|
|
|
|
foreach(glob($this->sd."/css/*.css") as $filename) {
|
|
$data = file_get_contents($filename);
|
|
preg_match_all("/(min|max)-width:([ ]+)?(([0-9]{1,5})(\.[0-9]{1,20}|)(px|em))/",$data,$matches);
|
|
foreach ($matches[3] as $match) {
|
|
if (!in_array($match,$mqs)) {
|
|
$mqs[] = $match;
|
|
}
|
|
}
|
|
}
|
|
|
|
sort($mqs);
|
|
return $mqs;
|
|
|
|
}
|
|
|
|
/**
|
|
* Refactoring the pattern path stuff
|
|
*/
|
|
protected function gatherPatternInfo() {
|
|
|
|
// make sure the pattern header & footer aren't added
|
|
$this->addPatternHF = false;
|
|
|
|
// set-up the defaults
|
|
$patternType = "";
|
|
$patternSubtype = "";
|
|
$patternSubtypeSet = false;
|
|
$dirSep = DIRECTORY_SEPARATOR;
|
|
|
|
// initialize various arrays
|
|
$this->navItems = array();
|
|
$this->navItems["patternTypes"] = array();
|
|
$this->patternPaths = array();
|
|
$this->patternTypes = array();
|
|
$this->patternLineages = array();
|
|
$this->patternPartials = array();
|
|
$this->viewAllPaths = array();
|
|
|
|
// iterate over the patterns & related data and regenerate the entire site if they've changed
|
|
$patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__.$this->sp), \RecursiveIteratorIterator::SELF_FIRST);
|
|
$patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS);
|
|
|
|
$patternObjects = iterator_to_array($patternObjects);
|
|
ksort($patternObjects);
|
|
|
|
foreach($patternObjects as $name => $object) {
|
|
|
|
$name = str_replace(__DIR__.$this->sp,"",$name);
|
|
$depth = substr_count($name,$dirSep);
|
|
|
|
// track old types and subtypes for increment purposes
|
|
|
|
if ($object->isDir() && ($depth == 0)) {
|
|
|
|
/*************************************
|
|
* This section is for:
|
|
* The pattern type directory
|
|
*************************************/
|
|
|
|
// is this the first bucket to be set?
|
|
$bi = (count($this->navItems["patternTypes"]) == 0) ? 0 : $bi + 1;
|
|
|
|
// set-up the names
|
|
$patternType = $name; // 00-atoms
|
|
$patternTypeDash = $this->getPatternName($name,false); // atoms
|
|
$patternTypeClean = str_replace("-"," ",$patternTypeDash); // atoms (dashes replaced with spaces)
|
|
|
|
// add to pattern types & pattern paths
|
|
$this->patternTypes[] = $patternType;
|
|
$this->patternPaths[$patternTypeDash] = array();
|
|
|
|
// add a new patternType to the nav
|
|
$this->navItems["patternTypes"][$bi] = array("patternTypeLC" => strtolower($patternTypeClean),
|
|
"patternTypeUC" => ucwords($patternTypeClean),
|
|
"patternType" => $patternType,
|
|
"patternTypeDash" => $patternTypeDash);
|
|
|
|
// starting a new set of pattern types. it might not have any pattern subtypes
|
|
$patternSubtypeSet = false;
|
|
|
|
} else if ($object->isDir() && ($depth == 1)) {
|
|
|
|
/*************************************
|
|
* This section is for:
|
|
* The pattern sub-type directory
|
|
*************************************/
|
|
|
|
// is this the first bucket to be set?
|
|
$ni = (!$patternSubtypeSet) ? 0 : $ni + 1;
|
|
|
|
// set-up the names
|
|
$patternSubtype = $object->getFilename(); // 02-blocks
|
|
$patternSubtypeDash = $this->getPatternName($object->getFilename(),false); // blocks
|
|
$patternSubtypeClean = str_replace("-"," ",$patternSubtypeDash); // blocks (dashes replaced with spaces)
|
|
|
|
// add to patternPartials
|
|
$this->patternPartials[$patternTypeDash."-".$patternSubtypeDash] = array();
|
|
|
|
// add a new patternSubtype to the nav
|
|
$this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni] = array("patternSubtypeLC" => strtolower($patternSubtypeClean),
|
|
"patternSubtypeUC" => ucwords($patternSubtypeClean),
|
|
"patternSubtype" => $patternSubtype,
|
|
"patternSubtypeDash" => $patternSubtypeDash);
|
|
|
|
// starting a new set of pattern types. it might not have any pattern subtypes
|
|
$patternSubtypeSet = true;
|
|
|
|
} else if ($object->isFile() && ($object->getExtension() == "mustache")) {
|
|
|
|
/*************************************
|
|
* This section is for:
|
|
* Mustache patterns
|
|
*************************************/
|
|
|
|
$patternFull = $object->getFilename(); // 00-colors.mustache
|
|
$pattern = str_replace(".mustache","",$patternFull); // 00-colors
|
|
|
|
// check for pattern state
|
|
$patternState = "";
|
|
if (strpos($pattern,"@") !== false) {
|
|
$patternBits = explode("@",$pattern,2);
|
|
$pattern = $patternBits[0];
|
|
$patternState = $patternBits[1];
|
|
}
|
|
|
|
if ($patternSubtypeSet) {
|
|
$patternPath = $patternType.$dirSep.$patternSubtype.$dirSep.$pattern; // 00-atoms/01-global/00-colors
|
|
$patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path)
|
|
} else {
|
|
$patternPath = $patternType.$dirSep.$pattern; // 00-atoms/00-colors
|
|
$patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-00-colors (file path)
|
|
}
|
|
|
|
// track to see if this pattern should get rendered
|
|
$render = false;
|
|
|
|
// make sure the pattern isn't hidden
|
|
if ($patternFull[0] != "_") {
|
|
|
|
// set-up the names
|
|
$patternDash = $this->getPatternName($pattern,false); // colors
|
|
$patternClean = str_replace("-"," ",$patternDash); // colors (dashes replaced with spaces)
|
|
$patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors
|
|
|
|
// set-up the info for the nav
|
|
$patternInfo = array("patternPath" => $patternPathDash."/".$patternPathDash.".html",
|
|
"patternSrcPath" => str_replace(__DIR__.$this->sp,"",$object->getPathname()),
|
|
"patternName" => ucwords($patternClean),
|
|
"patternState" => $patternState,
|
|
"patternPartial" => $patternPartial);
|
|
|
|
// add to the nav
|
|
if ($depth == 1) {
|
|
$this->navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo;
|
|
} else {
|
|
$this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo;
|
|
}
|
|
|
|
// add to the link var for inclusion in patterns
|
|
$this->d["link"][$patternPartial] = "../../patterns/".$patternPathDash."/".$patternPathDash.".html";
|
|
|
|
// yup, this pattern should get rendered
|
|
$render = true;
|
|
|
|
} else {
|
|
|
|
// replace the underscore to generate a good file pattern name
|
|
$patternDash = $this->getPatternName(str_replace("_","",$pattern),false); // colors
|
|
$patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors
|
|
|
|
}
|
|
|
|
// add all patterns to patternPaths
|
|
$patternSrcPath = str_replace(__DIR__.$this->sp,"",str_replace(".mustache","",$object->getPathname()));
|
|
$patternDestPath = $patternPathDash;
|
|
$this->patternPaths[$patternTypeDash][$patternDash] = array("patternSrcPath" => $patternSrcPath,
|
|
"patternDestPath" => $patternDestPath,
|
|
"patternPartial" => $patternPartial,
|
|
"patternState" => $patternState,
|
|
"patternType" => $patternTypeDash,
|
|
"render" => $render);
|
|
|
|
} else if ($object->isFile() && ($object->getExtension() == "json") && (strpos($object->getFilename(),"~") !== false)) {
|
|
|
|
/*************************************
|
|
* This section is for:
|
|
* JSON psuedo-patterns
|
|
*************************************/
|
|
|
|
$patternSubtypeInclude = ($patternSubtypeSet) ? $patternSubtype."-" : "";
|
|
$patternFull = $object->getFilename();
|
|
|
|
if ($patternFull[0] != "_") {
|
|
|
|
// check for a pattern state
|
|
$patternState = "";
|
|
$patternBits = explode("@",$patternFull,2);
|
|
if (isset($patternBits[1])) {
|
|
$patternState = str_replace(".json","",$patternBits[1]);
|
|
$patternFull = preg_replace("/@(.*?)\./",".",$patternFull);
|
|
}
|
|
|
|
// set-up the names
|
|
// $patternFull is defined above 00-colors.mustache
|
|
$patternBits = explode("~",$patternFull);
|
|
$patternBase = $patternBits[0].".mustache"; // 00-homepage.mustache
|
|
$patternBaseDash = $this->getPatternName($patternBits[0],false); // homepage
|
|
$patternBaseJSON = $patternBits[0].".json"; // 00-homepage.json
|
|
$stripJSON = str_replace(".json","",$patternBits[1]);
|
|
$patternBitClean = preg_replace("/@(.*?)/","",$patternBits[0]);
|
|
$pattern = $patternBitClean."-".$stripJSON; // 00-homepage-00-emergency
|
|
$patternInt = $patternBitClean."-".$this->getPatternName($stripJSON, false); // 00-homepage-emergency
|
|
$patternDash = $this->getPatternName($patternInt,false); // homepage-emergency
|
|
$patternClean = str_replace("-"," ",$patternDash); // homepage emergency
|
|
$patternPartial = $patternTypeDash."-".$patternDash; // pages-homepage-emergency
|
|
|
|
// add to patternPaths
|
|
if ($patternSubtypeSet) {
|
|
$patternPath = $patternType.$dirSep.$patternSubtype.$dirSep.$pattern; // 00-atoms/01-global/00-colors
|
|
$patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path)
|
|
} else {
|
|
$patternPath = $patternType.$dirSep.$pattern; // 00-atoms/00-colors
|
|
$patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-00-colors (file path)
|
|
}
|
|
|
|
// add all patterns to patternPaths
|
|
$patternSrcPath = $this->patternPaths[$patternTypeDash][$patternBaseDash]["patternSrcPath"];
|
|
$patternDestPath = $patternPathDash;
|
|
$this->patternPaths[$patternTypeDash][$patternDash] = array("patternSrcPath" => $patternSrcPath,
|
|
"patternDestPath" => $patternDestPath,
|
|
"patternPartial" => $patternPartial,
|
|
"patternState" => $patternState,
|
|
"patternType" => $patternTypeDash,
|
|
"render" => true);
|
|
|
|
// set-up the info for the nav
|
|
$patternInfo = array("patternPath" => $patternPathDash."/".$patternPathDash.".html",
|
|
"patternSrcPath" => str_replace(__DIR__.$this->sp,"",preg_replace("/\~(.*)\.json/",".mustache",$object->getPathname())),
|
|
"patternName" => ucwords($patternClean),
|
|
"patternState" => $patternState,
|
|
"patternPartial" => $patternPartial);
|
|
|
|
// add to the nav
|
|
if ($depth == 1) {
|
|
$this->navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo;
|
|
} else {
|
|
$this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo;
|
|
}
|
|
|
|
// add to the link var for inclusion in patterns
|
|
$this->d["link"][$patternPartial] = "../../patterns/".$patternPathDash."/".$patternPathDash.".html";
|
|
|
|
// get the base data
|
|
$patternDataBase = array();
|
|
if (file_exists($object->getPath()."/".$patternBaseJSON)) {
|
|
$patternDataBase = json_decode(file_get_contents($object->getPath()."/".$patternBaseJSON),true);
|
|
$this->jsonLastErrorMsg($patternBaseJSON);
|
|
}
|
|
|
|
// get the special pattern data
|
|
$patternData = (array) json_decode(file_get_contents($object->getPathname()));
|
|
$this->jsonLastErrorMsg($object->getFilename());
|
|
|
|
// merge them for the file
|
|
if (!isset($this->d["patternSpecific"][$patternPartial])) {
|
|
$this->d["patternSpecific"][$patternPartial] = array();
|
|
$this->d["patternSpecific"][$patternPartial]["data"] = array();
|
|
$this->d["patternSpecific"][$patternPartial]["listItems"] = array();
|
|
}
|
|
|
|
if (is_array($patternDataBase) && is_array($patternData)) {
|
|
$this->d["patternSpecific"][$patternPartial]["data"] = array_merge($patternDataBase, $patternData);
|
|
}
|
|
|
|
}
|
|
|
|
} else if ($object->isFile() && ($object->getExtension() == "json")) {
|
|
|
|
/*************************************
|
|
* This section is for:
|
|
* JSON data
|
|
*************************************/
|
|
$patternFull = $object->getFilename(); // 00-colors.mustache
|
|
$pattern = str_replace(".listitems","",str_replace(".json","",$patternFull)); // 00-colors
|
|
$patternDash = $this->getPatternName($pattern,false); // colors
|
|
$patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors
|
|
|
|
if ($patternFull[0] != "_") {
|
|
|
|
if (!isset($this->d["patternSpecific"][$patternPartial])) {
|
|
$this->d["patternSpecific"][$patternPartial] = array();
|
|
$this->d["patternSpecific"][$patternPartial]["data"] = array();
|
|
$this->d["patternSpecific"][$patternPartial]["listItems"] = array();
|
|
}
|
|
|
|
if (strpos($object->getFilename(),".listitems.json") !== false) {
|
|
$patternData = $this->getListItems($object->getPathname());
|
|
$this->d["patternSpecific"][$patternPartial]["listItems"] = $patternData;
|
|
} else {
|
|
$patternData = json_decode(file_get_contents($object->getPathname()),true);
|
|
$this->jsonLastErrorMsg($patternFull);
|
|
$this->d["patternSpecific"][$patternPartial]["data"] = $patternData;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// get all of the lineages
|
|
$this->gatherLineages();
|
|
|
|
// check on the states of the patterns
|
|
$patternStateLast = count($this->patternStates) - 1;
|
|
foreach($this->patternPaths as $patternType => $patterns) {
|
|
|
|
foreach ($patterns as $pattern => $patternInfo) {
|
|
|
|
$patternState = $this->patternPaths[$patternType][$pattern]["patternState"];
|
|
|
|
// make sure the pattern has a given state
|
|
if ($patternState != "") {
|
|
|
|
$patternStateDigit = array_search($patternState, $this->patternStates);
|
|
if ($patternStateDigit !== false) {
|
|
// iterate over each of the reverse lineages for a given pattern to update their state
|
|
foreach ($this->patternLineagesR[$patternType."-".$pattern] as $patternCheckInfo) {
|
|
$patternBits = $this->getPatternInfo($patternCheckInfo["lineagePattern"]);
|
|
if (($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] == "") && ($patternStateDigit != $patternStateLast)) {
|
|
$this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] = $patternState;
|
|
} else {
|
|
$patternStateCheck = array_search($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"], $this->patternStates);
|
|
if ($patternStateDigit < $patternStateCheck) {
|
|
$this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] = $patternState;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// make sure we update the lineages with the pattern state if appropriate
|
|
foreach($this->patternLineages as $pattern => $patternLineages) {
|
|
foreach($patternLineages as $key => $patternLineageInfo) {
|
|
$patternBits = $this->getPatternInfo($patternLineageInfo["lineagePattern"]);
|
|
$patternState = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"];
|
|
if (($patternState != "") && ($patternState != null)) {
|
|
$this->patternLineages[$pattern][$key]["lineageState"] = $patternState;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach($this->patternLineagesR as $pattern => $patternLineages) {
|
|
foreach($patternLineages as $key => $patternLineageInfo) {
|
|
$patternBits = $this->getPatternInfo($patternLineageInfo["lineagePattern"]);
|
|
$patternState = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"];
|
|
if (($patternState != "") && ($patternState != null)) {
|
|
$this->patternLineagesR[$pattern][$key]["lineageState"] = $patternState;
|
|
}
|
|
}
|
|
}
|
|
|
|
// make sure $this->mpl is refreshed
|
|
$this->loadMustachePatternLoaderInstance();
|
|
|
|
// run through the nav items and generate pattern partials and the view all pages
|
|
foreach ($this->navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) {
|
|
|
|
$patternType = $patternTypeValues["patternType"];
|
|
$patternTypeDash = $patternTypeValues["patternTypeDash"];
|
|
|
|
// if this has a second level of patterns check them out (means we don't process pages & templates)
|
|
if (isset($patternTypeValues["patternTypeItems"]) && (!in_array($patternType,$this->styleGuideExcludes))) {
|
|
|
|
$arrayReset = false;
|
|
|
|
foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) {
|
|
|
|
// if there are no sub-items in a section remove it, else do a bunch of other stuff
|
|
if (!isset($patternSubtypeValues["patternSubtypeItems"])) {
|
|
|
|
unset($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]);
|
|
$arrayReset = true;
|
|
|
|
} else {
|
|
|
|
$patternSubtype = $patternSubtypeValues["patternSubtype"];
|
|
$patternSubtypeDash = $patternSubtypeValues["patternSubtypeDash"];
|
|
$subItemsCount = count($patternSubtypeValues["patternSubtypeItems"]);
|
|
|
|
// add a view all link
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$subItemsCount] = array(
|
|
"patternPath" => $patternType."-".$patternSubtype."/index.html",
|
|
"patternName" => "View All",
|
|
"patternType" => $patternType,
|
|
"patternSubtype" => $patternSubtype,
|
|
"patternPartial" => "viewall-".$patternTypeDash."-".$patternSubtypeDash);
|
|
|
|
// add to the view all paths
|
|
$this->viewAllPaths[$patternTypeDash][$patternSubtypeDash] = $patternType."-".$patternSubtype;
|
|
|
|
// add patterns to $this->patternPartials
|
|
foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItem) {
|
|
|
|
$patternCode = $this->renderPattern($patternSubtypeItem["patternSrcPath"],$patternSubtypeItem["patternPartial"]);
|
|
$patternCodeRaw = $patternCode[0];
|
|
$patternCodeEncoded = $patternCode[1];
|
|
$patternLineageExists = (count($this->patternLineages[$patternSubtypeItem["patternPartial"]]) > 0) ? true : false;
|
|
$patternLineages = $this->patternLineages[$patternSubtypeItem["patternPartial"]];
|
|
|
|
// set-up the mark-up for CSS Rule Saver so it can figure out which rules to save
|
|
$patternCSSExists = $this->enableCSS;
|
|
$patternCSS = "";
|
|
if ($this->enableCSS) {
|
|
$this->cssRuleSaver->loadHTML($patternCodeRaw,false);
|
|
$patternCSS = $this->cssRuleSaver->saveRules();
|
|
$this->patternCSS[$patternSubtypeItem["patternPartial"]] = $patternCSS;
|
|
}
|
|
|
|
$this->patternPartials[$patternTypeDash."-".$patternSubtypeDash][] = array("patternName" => $patternSubtypeItem["patternName"],
|
|
"patternLink" => $patternSubtypeItem["patternPath"],
|
|
"patternPartial" => $patternSubtypeItem["patternPartial"],
|
|
"patternPartialCode" => $patternCodeRaw,
|
|
"patternPartialCodeE" => $patternCodeEncoded,
|
|
"patternCSSExists" => $patternCSSExists,
|
|
"patternCSS" => $patternCSS,
|
|
"patternLineageExists" => $patternLineageExists,
|
|
"patternLineages" => $patternLineages
|
|
);
|
|
|
|
// set the pattern state
|
|
$patternBits = $this->getPatternInfo($patternSubtypeItem["patternPartial"]);
|
|
if (($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] != "") && (isset($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"]))) {
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"];
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// reset the items to take into account removed items affecting the index
|
|
if ($arrayReset) {
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"] = array_values($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"]);
|
|
$arrayReset = false;
|
|
}
|
|
|
|
} else {
|
|
|
|
foreach ($patternTypeValues["patternItems"] as $patternSubtypeKey => $patternSubtypeItem) {
|
|
// set the pattern state
|
|
$patternBits = $this->getPatternInfo($patternSubtypeItem["patternPartial"]);
|
|
if ($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] != "") {
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"];
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// load pattern-lab's resources
|
|
$htmlHead = file_get_contents(__DIR__."/../../templates/pattern-header-footer/header.html");
|
|
$htmlFoot = file_get_contents(__DIR__."/../../templates/pattern-header-footer/footer.html");
|
|
$extraFoot = file_get_contents(__DIR__."/../../templates/pattern-header-footer/footer-pattern.html");
|
|
|
|
// gather the user-defined header and footer information
|
|
$patternHeadPath = __DIR__.$this->sp."00-atoms/00-meta/_00-head.mustache";
|
|
$patternFootPath = __DIR__.$this->sp."00-atoms/00-meta/_01-foot.mustache";
|
|
$patternHead = (file_exists($patternHeadPath)) ? file_get_contents($patternHeadPath) : "";
|
|
$patternFoot = (file_exists($patternFootPath)) ? file_get_contents($patternFootPath) : "";
|
|
|
|
// add pattern lab's resource to the user-defined files
|
|
$this->patternHead = str_replace("{% pattern-lab-head %}",$htmlHead,$patternHead);
|
|
$this->patternFoot = str_replace("{% pattern-lab-foot %}",$extraFoot.$htmlFoot,$patternFoot);
|
|
$this->mainPageHead = $this->patternHead;
|
|
$this->mainPageFoot = str_replace("{% pattern-lab-foot %}",$htmlFoot,$patternFoot);
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the lineage for a given pattern by parsing it and matching mustache partials
|
|
* @param {String} the filename for the pattern to be parsed
|
|
*
|
|
* @return {Array} a list of patterns
|
|
*/
|
|
protected function getLineage($filename) {
|
|
$data = file_get_contents(__DIR__.$this->sp.$filename.".mustache");
|
|
//$data = file_get_contents($filename);
|
|
if (preg_match_all('/{{>([ ]+)?([A-Za-z0-9-]+)(?:\:[A-Za-z0-9-]+)?(?:(| )\(.*)?([ ]+)}}/',$data,$matches)) {
|
|
return $matches[2];
|
|
}
|
|
return array();
|
|
}
|
|
|
|
/**
|
|
* Get the lineage for a given pattern by parsing it and matching mustache partials
|
|
* @param {String} the filename for the pattern to be parsed
|
|
*
|
|
* @return {Array} the final set of list items
|
|
*/
|
|
protected function getListItems($filepath) {
|
|
|
|
$listItems = array();
|
|
|
|
// add list item data, makes 'listItems' a reserved word
|
|
if (file_exists($filepath)) {
|
|
|
|
$listItemsJSON = json_decode(file_get_contents($filepath), true);
|
|
$this->jsonLastErrorMsg(str_replace($this->sd."/","",$filepath));
|
|
|
|
$numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve");
|
|
|
|
$i = 0;
|
|
$k = 1;
|
|
$c = count($listItemsJSON)+1;
|
|
|
|
while ($k < $c) {
|
|
|
|
shuffle($listItemsJSON);
|
|
$itemsArray = array();
|
|
//$listItems[$numbers[$k-1]] = array();
|
|
|
|
while ($i < $k) {
|
|
$itemsArray[] = $listItemsJSON[$i];
|
|
$i++;
|
|
}
|
|
|
|
$listItems[$numbers[$k-1]] = $itemsArray;
|
|
|
|
$i = 0;
|
|
$k++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $listItems;
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the directory path for a given pattern or json file by parsing the file path
|
|
* @param {String} the filepath for a directory that contained the match
|
|
* @param {String} the type of match for the pattern matching, defaults to mustache
|
|
*
|
|
* @return {String} the directory for the pattern
|
|
*/
|
|
protected function getPath($filepath,$type = "m") {
|
|
$file = ($type == 'm') ? '\.mustache' : '\.json';
|
|
if (preg_match('/\/('.$this->patternTypesRegex.'\/(([A-z0-9-]{1,})\/|)([A-z0-9-]{1,}))'.$file.'$/',$filepath,$matches)) {
|
|
return $matches[1];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to return the parts of a partial name
|
|
* @param {String} the name of the partial
|
|
*
|
|
* @return {Array} the pattern type and the name of the pattern
|
|
*/
|
|
private function getPatternInfo($name) {
|
|
|
|
$patternBits = explode("-",$name);
|
|
|
|
$i = 1;
|
|
$k = 2;
|
|
$c = count($patternBits);
|
|
$patternType = $patternBits[0];
|
|
while (!isset($this->patternPaths[$patternType]) && ($i < $c)) {
|
|
$patternType .= "-".$patternBits[$i];
|
|
$i++;
|
|
$k++;
|
|
}
|
|
|
|
$patternBits = explode("-",$name,$k);
|
|
$pattern = $patternBits[count($patternBits)-1];
|
|
|
|
return array($patternType, $pattern);
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the name for a given pattern sans any possible digits used for reordering
|
|
* @param {String} the pattern based on the filesystem name
|
|
* @param {Boolean} whether or not to strip slashes from the pattern name
|
|
*
|
|
* @return {String} a lower-cased version of the pattern name
|
|
*/
|
|
protected function getPatternName($pattern, $clean = true) {
|
|
$patternBits = explode("-",$pattern,2);
|
|
$patternName = (((int)$patternBits[0] != 0) || ($patternBits[0] == '00')) ? $patternBits[1] : $pattern;
|
|
return ($clean) ? (str_replace("-"," ",$patternName)) : $patternName;
|
|
}
|
|
|
|
protected function setPatternState($patternState, $patternPartial) {
|
|
|
|
// set-up some defaults
|
|
$patternState = array_search($patternState, $this->patternStates);
|
|
|
|
// iterate over each of the reverse lineages for a given pattern to update their state
|
|
foreach ($this->patternLineagesR[$patternPartial] as $patternCheckInfo) {
|
|
|
|
// run through all of the navitems to find what pattern states match. this feels, and is, overkill
|
|
foreach ($this->navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) {
|
|
|
|
if (isset($patternTypeValues["patternTypeItems"])) {
|
|
|
|
foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) {
|
|
|
|
// add patterns to $this->patternPartials
|
|
foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItem) {
|
|
|
|
if ($patternSubtypeItem["patternPartial"] == $patternPartial) {
|
|
|
|
if ($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] == "") {
|
|
$f = $patternState;
|
|
} else {
|
|
$patternCheckState = array_search($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"], $this->patternStates);
|
|
if ($patternState < $patternCheckState) {
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] = $patternState;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
foreach ($patternTypeValues["patternItems"] as $patternSubtypeKey => $patternSubtypeItem) {
|
|
|
|
if ($patternSubtypeItem["patternPartial"] == $patternPartial) {
|
|
|
|
if ($this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] == "") {
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $patternState;
|
|
} else {
|
|
$patternCheckState = array_search($this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"], $this->patternStates);
|
|
if ($patternState < $patternCheckState) {
|
|
$this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $patternState;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Write out the time tracking file so the content sync service will work. A holdover
|
|
* from how I put together the original AJAX polling set-up.
|
|
*/
|
|
protected function updateChangeTime() {
|
|
|
|
if (is_dir($this->pd."/")) {
|
|
file_put_contents($this->pd."/latest-change.txt",time());
|
|
} else {
|
|
print "Either the public directory for Pattern Lab doesn't exist or the builder is in the wrong location. Please fix.";
|
|
exit;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Delete patterns and user-created directories and files in public/
|
|
*/
|
|
protected function cleanPublic() {
|
|
|
|
// make sure patterns exists before trying to clean it
|
|
if (is_dir($this->pd."/patterns")) {
|
|
|
|
$objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->pd."/patterns/"), \RecursiveIteratorIterator::CHILD_FIRST);
|
|
|
|
// make sure dots are skipped
|
|
$objects->setFlags(\FilesystemIterator::SKIP_DOTS);
|
|
|
|
// for each file figure out what to do with it
|
|
foreach($objects as $name => $object) {
|
|
|
|
if ($object->isDir()) {
|
|
// if this is a directory remove it
|
|
rmdir($name);
|
|
} else if ($object->isFile() && ($object->getFilename() != "README")) {
|
|
// if this is a file remove it
|
|
unlink($name);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// scan source/ & public/ to figure out what directories might need to be cleaned up
|
|
$sourceDirs = glob($this->sd."/*",GLOB_ONLYDIR);
|
|
$publicDirs = glob($this->pd."/*",GLOB_ONLYDIR);
|
|
|
|
// make sure some directories aren't deleted
|
|
$ignoreDirs = array("styleguide");
|
|
foreach ($ignoreDirs as $ignoreDir) {
|
|
$key = array_search($this->pd."/".$ignoreDir,$publicDirs);
|
|
if ($key !== false){
|
|
unset($publicDirs[$key]);
|
|
}
|
|
}
|
|
|
|
// compare source dirs against public. remove those dirs w/ an underscore in source/ from the public/ list
|
|
foreach ($sourceDirs as $sourceDir) {
|
|
$cleanDir = str_replace($this->sd."/","",$sourceDir);
|
|
if ($cleanDir[0] == "_") {
|
|
$key = array_search($this->pd."/".str_replace("_","",$cleanDir),$publicDirs);
|
|
if ($key !== false){
|
|
unset($publicDirs[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// for the remaining dirs in public delete them and their files
|
|
foreach ($publicDirs as $dir) {
|
|
|
|
$objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::CHILD_FIRST);
|
|
|
|
// make sure dots are skipped
|
|
$objects->setFlags(\FilesystemIterator::SKIP_DOTS);
|
|
|
|
foreach($objects as $name => $object) {
|
|
|
|
if ($object->isDir()) {
|
|
rmdir($name);
|
|
} else if ($object->isFile()) {
|
|
unlink($name);
|
|
}
|
|
|
|
}
|
|
|
|
rmdir($dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Copies a file from the given source path to the given public path.
|
|
* THIS IS NOT FOR PATTERNS
|
|
* @param {String} the source file
|
|
* @param {String} the public file
|
|
*/
|
|
protected function moveFile($s,$p) {
|
|
if (file_exists($this->sd."/".$s)) {
|
|
copy($this->sd."/".$s,$this->pd."/".$p);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Moves static files that aren't directly related to Pattern Lab
|
|
* @param {String} file name to be moved
|
|
* @param {String} copy for the message to be printed out
|
|
* @param {String} part of the file name to be found for replacement
|
|
* @param {String} the replacement
|
|
*/
|
|
protected function moveStaticFile($fileName,$copy = "", $find = "", $replace = "") {
|
|
$this->moveFile($fileName,str_replace($find, $replace, $fileName));
|
|
$this->updateChangeTime();
|
|
if ($copy != "") {
|
|
print $fileName." ".$copy."...\n";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check to see if a given filename is in a directory that should be ignored
|
|
* @param {String} file name to be checked
|
|
*
|
|
* @return {Boolean} whether the directory should be ignored
|
|
*/
|
|
protected function ignoreDir($fileName) {
|
|
foreach($this->id as $dir) {
|
|
$pos = strpos(DIRECTORY_SEPARATOR.$fileName,DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR);
|
|
if ($pos !== false) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Loads the CSS from source/css/ into CSS Rule Saver to be used for code view
|
|
*/
|
|
protected function initializeCSSRuleSaver() {
|
|
|
|
$loader = new \SplClassLoader('CSSRuleSaver', __DIR__.'/../../lib');
|
|
$loader->register();
|
|
|
|
$this->cssRuleSaver = new \CSSRuleSaver\CSSRuleSaver;
|
|
|
|
foreach(glob($this->sd."/css/*.css") as $filename) {
|
|
$this->cssRuleSaver->loadCSS($filename);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the last error message when building a JSON file. Mimics json_last_error_msg() from PHP 5.5
|
|
* @param {String} the file that generated the error
|
|
*/
|
|
protected function jsonLastErrorMsg($file) {
|
|
$errors = array(
|
|
JSON_ERROR_NONE => null,
|
|
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
|
|
JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
|
|
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
|
|
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
|
|
JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
|
|
);
|
|
$error = json_last_error();
|
|
$errorMessage = array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})";
|
|
if ($errorMessage != null) {
|
|
print "The JSON file, ".$file.", wasn't loaded. The error: ".$errorMessage."\n";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print out the data var. For debugging purposes
|
|
*
|
|
* @return {String} the formatted version of the d object
|
|
*/
|
|
public function printData() {
|
|
print_r($this->d);
|
|
}
|
|
|
|
/**
|
|
* Trim a given string. Used in the array_walk() function in __construct as a sanity check
|
|
* @param {String} an entry from one of the list-based config entries
|
|
*
|
|
* @return {String} trimmed version of the given $v var
|
|
*/
|
|
public function trim(&$v) {
|
|
$v = trim($v);
|
|
}
|
|
|
|
/**
|
|
* Lowercase the given string. Used in the array_walk() function in __construct as a sanity check
|
|
* @param {String} an entry from one of the list-based config entries
|
|
*
|
|
* @return {String} lowercased version of the given $v var
|
|
*/
|
|
public function strtolower(&$v) {
|
|
$v = strtolower($v);
|
|
}
|
|
|
|
}
|