mirror of
https://github.com/janishutz/color-thief.git
synced 2025-11-25 13:54:25 +00:00
updates before renaming to color-thief
This commit is contained in:
197
css/app.css
197
css/app.css
@@ -63,43 +63,214 @@ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav,
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* line 3, ../sass/app.sass */
|
/* =Global */
|
||||||
body {
|
/* line 9, ../sass/app.sass */
|
||||||
color: #444444;
|
body, input, textarea {
|
||||||
font-family: "lucida grande", sans-serif;
|
margin: 40px;
|
||||||
line-height: 1.625em;
|
color: #555555;
|
||||||
padding: 40px;
|
font: 16px/1.625em "Varela Round", "lucida grande", tahoma, sans-serif;
|
||||||
|
font-weight: 400;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* line 9, ../sass/app.sass */
|
/* line 17, ../sass/app.sass */
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: "Terminal Dosis", "lucida grande", tahoma, sans-serif;
|
||||||
|
line-height: 1em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 23, ../sass/app.sass */
|
||||||
|
h1 {
|
||||||
|
font-size: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 26, ../sass/app.sass */
|
||||||
|
h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 30, ../sass/app.sass */
|
||||||
|
h3 {
|
||||||
|
font-size: 18px;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 34, ../sass/app.sass */
|
||||||
|
p {
|
||||||
|
margin-bottom: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 38, ../sass/app.sass */
|
||||||
|
strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms */
|
||||||
|
/* line 44, ../sass/app.sass */
|
||||||
|
input[type=text],
|
||||||
|
input[type=password],
|
||||||
|
textarea {
|
||||||
|
background: #fafafa;
|
||||||
|
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
-o-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
color: #888888;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-o-border-radius: 4px;
|
||||||
|
-ms-border-radius: 4px;
|
||||||
|
-khtml-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 55, ../sass/app.sass */
|
||||||
|
input[type=text]:focus,
|
||||||
|
textarea:focus {
|
||||||
|
color: #373737;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 59, ../sass/app.sass */
|
||||||
|
textarea {
|
||||||
|
padding-left: 3px;
|
||||||
|
width: 98%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 63, ../sass/app.sass */
|
||||||
|
input[type=text] {
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
/* line 67, ../sass/app.sass */
|
||||||
|
a {
|
||||||
|
color: #555555;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
/* line 70, ../sass/app.sass */
|
||||||
|
a:hover {
|
||||||
|
color: #09a1ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 75, ../sass/app.sass */
|
||||||
|
.button {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-family: "Terminal Dosis", "lucida grande", tahoma, sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
olor: #555555;
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0.6em 1.5em 0.5em 1.5em;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
-moz-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.1), 0 2px 5px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
-webkit-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.1), 0 2px 5px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
-o-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.1), 0 2px 5px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.1), 0 2px 5px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
background-color: #eeeeee;
|
||||||
|
-moz-border-radius: 4px;
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
-o-border-radius: 4px;
|
||||||
|
-ms-border-radius: 4px;
|
||||||
|
-khtml-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #d6d6d6;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
/* line 92, ../sass/app.sass */
|
||||||
|
.button:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
/* line 94, ../sass/app.sass */
|
||||||
|
.button:active {
|
||||||
|
-moz-box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
-webkit-box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
-o-box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
box-shadow: inset 0 2px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
top: 2px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buttons with dark backgrounds */
|
||||||
|
/* line 103, ../sass/app.sass */
|
||||||
|
.button.nav,
|
||||||
|
.button.warn,
|
||||||
|
.button.primary,
|
||||||
|
.nav-previous .button,
|
||||||
|
.nav-next .button {
|
||||||
|
color: white;
|
||||||
|
text-shadow: rgba(0, 0, 0, 0.2) 1px 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 112, ../sass/app.sass */
|
||||||
|
.button.nav,
|
||||||
|
.nav-previous .button,
|
||||||
|
.nav-next .button {
|
||||||
|
background-color: #09a1ec;
|
||||||
|
border-color: #0891d4;
|
||||||
|
}
|
||||||
|
/* line 117, ../sass/app.sass */
|
||||||
|
.button.nav:hover,
|
||||||
|
.nav-previous .button:hover,
|
||||||
|
.nav-next .button:hover {
|
||||||
|
background-color: #33b6f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 123, ../sass/app.sass */
|
||||||
|
.button.warn {
|
||||||
|
background-color: #ee8833;
|
||||||
|
border-color: #ec7818;
|
||||||
|
}
|
||||||
|
/* line 126, ../sass/app.sass */
|
||||||
|
.button.warn:hover {
|
||||||
|
background-color: #f1a05c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 131, ../sass/app.sass */
|
||||||
|
.button.primary {
|
||||||
|
background-color: #6bb445;
|
||||||
|
border-color: #6bb445;
|
||||||
|
}
|
||||||
|
/* line 134, ../sass/app.sass */
|
||||||
|
.button.primary:hover {
|
||||||
|
background-color: #88c568;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* line 143, ../sass/app.sass */
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* line 16, ../sass/app.sass */
|
/* line 150, ../sass/app.sass */
|
||||||
.imageSection {
|
.imageSection {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
*zoom: 1;
|
*zoom: 1;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
/* line 19, ../sass/app.sass */
|
/* line 153, ../sass/app.sass */
|
||||||
.imageSection img {
|
.imageSection img {
|
||||||
float: left;
|
float: left;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
}
|
}
|
||||||
/* line 22, ../sass/app.sass */
|
/* line 156, ../sass/app.sass */
|
||||||
.imageSection .colors {
|
.imageSection .colors {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
/* line 25, ../sass/app.sass */
|
/* line 159, ../sass/app.sass */
|
||||||
.imageSection .colors .function {
|
.imageSection .colors .function {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
*zoom: 1;
|
*zoom: 1;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
/* line 28, ../sass/app.sass */
|
/* line 162, ../sass/app.sass */
|
||||||
.imageSection .colors .function .swatch {
|
.imageSection .colors .function .swatch {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@@ -108,7 +279,7 @@ h1 {
|
|||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* line 35, ../sass/app.sass */
|
/* line 169, ../sass/app.sass */
|
||||||
canvas {
|
canvas {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
48
index.html
48
index.html
@@ -4,6 +4,8 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=Varela+Round|Terminal+Dosis:400,700,600' rel='stylesheet' type='text/css'>
|
||||||
|
|
||||||
<title>Image Palette</title>
|
<title>Image Palette</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="author" content="">
|
<meta name="author" content="">
|
||||||
@@ -26,15 +28,11 @@
|
|||||||
<div class="imageSection">
|
<div class="imageSection">
|
||||||
<img src="img/icon1.png" />
|
<img src="img/icon1.png" />
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="function averageRGB">
|
|
||||||
<h3>getAverageRGB()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function dominantColor">
|
<div class="function dominantColor">
|
||||||
<h3>getDominantColor()</h3>
|
<h3>getDominantColor()</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="function areaBasedPalette">
|
|
||||||
<h3>createAreaBasedPalette()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function medianCutPalette">
|
<div class="function medianCutPalette">
|
||||||
<h3>createMedianCutPalette()</h3>
|
<h3>createMedianCutPalette()</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,15 +42,11 @@
|
|||||||
<div class="imageSection">
|
<div class="imageSection">
|
||||||
<img src="img/icon2.gif" />
|
<img src="img/icon2.gif" />
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="function averageRGB">
|
|
||||||
<h3>getAverageRGB()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function dominantColor">
|
<div class="function dominantColor">
|
||||||
<h3>getDominantColor()</h3>
|
<h3>getDominantColor()</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="function areaBasedPalette">
|
|
||||||
<h3>createAreaBasedPalette()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function medianCutPalette">
|
<div class="function medianCutPalette">
|
||||||
<h3>createMedianCutPalette()</h3>
|
<h3>createMedianCutPalette()</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,15 +56,11 @@
|
|||||||
<div class="imageSection">
|
<div class="imageSection">
|
||||||
<img src="img/icon3.png" />
|
<img src="img/icon3.png" />
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="function averageRGB">
|
|
||||||
<h3>getAverageRGB()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function dominantColor">
|
<div class="function dominantColor">
|
||||||
<h3>getDominantColor()</h3>
|
<h3>getDominantColor()</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="function areaBasedPalette">
|
|
||||||
<h3>createAreaBasedPalette()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function medianCutPalette">
|
<div class="function medianCutPalette">
|
||||||
<h3>createMedianCutPalette()</h3>
|
<h3>createMedianCutPalette()</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -80,15 +70,9 @@
|
|||||||
<div class="imageSection">
|
<div class="imageSection">
|
||||||
<img src="img/4.png" />
|
<img src="img/4.png" />
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="function averageRGB">
|
|
||||||
<h3>getAverageRGB()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function dominantColor">
|
<div class="function dominantColor">
|
||||||
<h3>getDominantColor()</h3>
|
<h3>getDominantColor()</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="function areaBasedPalette">
|
|
||||||
<h3>createAreaBasedPalette()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function medianCutPalette">
|
<div class="function medianCutPalette">
|
||||||
<h3>createMedianCutPalette()</h3>
|
<h3>createMedianCutPalette()</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,15 +82,9 @@
|
|||||||
<div class="imageSection">
|
<div class="imageSection">
|
||||||
<img src="img/5.png" />
|
<img src="img/5.png" />
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="function averageRGB">
|
|
||||||
<h3>getAverageRGB()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function dominantColor">
|
<div class="function dominantColor">
|
||||||
<h3>getDominantColor()</h3>
|
<h3>getDominantColor()</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="function areaBasedPalette">
|
|
||||||
<h3>createAreaBasedPalette()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function medianCutPalette">
|
<div class="function medianCutPalette">
|
||||||
<h3>createMedianCutPalette()</h3>
|
<h3>createMedianCutPalette()</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -116,15 +94,9 @@
|
|||||||
<div class="imageSection">
|
<div class="imageSection">
|
||||||
<img src="img/6.jpeg" />
|
<img src="img/6.jpeg" />
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="function averageRGB">
|
|
||||||
<h3>getAverageRGB()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function dominantColor">
|
<div class="function dominantColor">
|
||||||
<h3>getDominantColor()</h3>
|
<h3>getDominantColor()</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="function areaBasedPalette">
|
|
||||||
<h3>createAreaBasedPalette()</h3>
|
|
||||||
</div>
|
|
||||||
<div class="function medianCutPalette">
|
<div class="function medianCutPalette">
|
||||||
<h3>createMedianCutPalette()</h3>
|
<h3>createMedianCutPalette()</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -139,7 +111,9 @@
|
|||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
|
||||||
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.2.min.js"><\/script>')</script>
|
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.2.min.js"><\/script>')</script>
|
||||||
|
|
||||||
<script src="js/quantize.js"></script>
|
<script src="js/libs/quantize.js"></script>
|
||||||
|
<script src="js/libs/jquery.imagesloaded.js"></script>
|
||||||
|
<script src="js/libs/mustache.js"></script>
|
||||||
|
|
||||||
<script src="js/canvasimage.js"></script>
|
<script src="js/canvasimage.js"></script>
|
||||||
<script src="js/functions.js"></script>
|
<script src="js/functions.js"></script>
|
||||||
|
|||||||
66
js/app.js
66
js/app.js
@@ -1,46 +1,46 @@
|
|||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
|
||||||
|
var view = {
|
||||||
|
title: "Joe",
|
||||||
|
calc: function() {
|
||||||
|
return 2 + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var template = "{{title}} spends {{calc}}";
|
||||||
|
|
||||||
|
var html = Mustache.to_html(template, view);
|
||||||
|
|
||||||
|
$('body').prepend(html);
|
||||||
|
|
||||||
$('img').each(function(index){
|
$('img').imagesLoaded(function(){
|
||||||
|
|
||||||
|
$('img').each(function(index){
|
||||||
|
|
||||||
var averageRGB = getAverageRGB(this);
|
var dominantColor = getDominantColor(this);
|
||||||
var dominantColor = getDominantColor(this);
|
var medianPalette = createPalette(this, 10);
|
||||||
var areaPalette = createAreaBasedPalette(this, 9);
|
|
||||||
var medianPalette = createMedianCutPalette(this, 10);
|
|
||||||
|
|
||||||
var imageSection = $(this).closest('.imageSection');
|
var imageSection = $(this).closest('.imageSection');
|
||||||
|
|
||||||
var swatchEl = $('<div>', {
|
|
||||||
'class': 'swatch'
|
|
||||||
}).css('background-color','rgba('+averageRGB.r+','+averageRGB.g+ ','+averageRGB.b+', 1)');
|
|
||||||
|
|
||||||
imageSection.find('.averageRGB').append(swatchEl);
|
var switchEl;
|
||||||
|
|
||||||
swatchEl = $('<div>', {
|
|
||||||
'class': 'swatch'
|
|
||||||
}).css('background-color','rgba('+dominantColor.r+','+dominantColor.g+ ','+dominantColor.b+', 1)');
|
|
||||||
|
|
||||||
imageSection.find('.dominantColor').append(swatchEl);
|
|
||||||
|
|
||||||
|
|
||||||
var areaBasedPalette = imageSection.find('.areaBasedPalette');
|
|
||||||
|
|
||||||
$.each(areaPalette, function(index, value){
|
|
||||||
swatchEl = $('<div>', {
|
swatchEl = $('<div>', {
|
||||||
'class': 'swatch'
|
'class': 'swatch'
|
||||||
}).css('background-color','rgba('+value.r+','+value.g+ ','+value.b+', 1)');
|
}).css('background-color','rgba('+dominantColor.r+','+dominantColor.g+ ','+dominantColor.b+', 1)');
|
||||||
areaBasedPalette.append(swatchEl);
|
|
||||||
});
|
|
||||||
|
|
||||||
var medianCutPalette = imageSection.find('.medianCutPalette');
|
|
||||||
|
|
||||||
$.each(medianPalette, function(index, value){
|
imageSection.find('.dominantColor').append(swatchEl);
|
||||||
swatchEl = $('<div>', {
|
|
||||||
'class': 'swatch'
|
|
||||||
}).css('background-color','rgba('+value[0]+','+value[1]+ ','+value[2]+', 1)');
|
|
||||||
medianCutPalette.append(swatchEl);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
var medianCutPalette = imageSection.find('.medianCutPalette');
|
||||||
|
|
||||||
|
$.each(medianPalette, function(index, value){
|
||||||
|
swatchEl = $('<div>', {
|
||||||
|
'class': 'swatch'
|
||||||
|
}).css('background-color','rgba('+value[0]+','+value[1]+ ','+value[2]+', 1)');
|
||||||
|
medianCutPalette.append(swatchEl);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
196
js/color-thief.js
Normal file
196
js/color-thief.js
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Image Palette v0.1
|
||||||
|
* by Lokesh Dhakar - http://www.lokeshdhakar.com
|
||||||
|
*
|
||||||
|
* Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
|
||||||
|
*
|
||||||
|
* The median cut palette function uses quantize.js which is written by Nick Rabinowitz
|
||||||
|
* and licensed under the MIT license. Big props to Nick as this is where the magic happens.
|
||||||
|
*
|
||||||
|
* == Functions
|
||||||
|
* getDominantColor()
|
||||||
|
* createPalette()
|
||||||
|
* getAverageRGB()
|
||||||
|
* createAreaBasedPalette()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getDominantColor(sourceImage)
|
||||||
|
* returns {r: num, g: num, b: num}
|
||||||
|
*
|
||||||
|
* Use the median cut algorithm provided by quantize.js to cluster similar
|
||||||
|
* colors and return the base color from the largest cluster.
|
||||||
|
*/
|
||||||
|
function getDominantColor(sourceImage){
|
||||||
|
|
||||||
|
var palette = [];
|
||||||
|
|
||||||
|
// Create custom CanvasImage object
|
||||||
|
var image = new CanvasImage(sourceImage),
|
||||||
|
imageData = image.getImageData(),
|
||||||
|
pixels = imageData.data,
|
||||||
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
|
// Store the RGB values in an array format suitable for quantize function
|
||||||
|
var pixelArray = [];
|
||||||
|
for (var i = 0; i < pixelCount; i++) {
|
||||||
|
// If pixel is mostly opaque
|
||||||
|
if(pixels[i*4+3] >= 125){
|
||||||
|
pixelArray.push( [pixels[i*4], pixels[i*4+1], pixels[i*4+2]]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send array to quantize function which clusters values
|
||||||
|
// using median cut algorithm
|
||||||
|
var cmap = MMCQ.quantize(pixelArray, 5);
|
||||||
|
var newPalette = cmap.palette();
|
||||||
|
|
||||||
|
return {r: newPalette[0][0], g: newPalette[0][1], b: newPalette[0][2]};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* createPalette(sourceImage)
|
||||||
|
* returns array[ {r: num, g: num, b: num}, {r: num, g: num, b: num}, ...]
|
||||||
|
*
|
||||||
|
* Use the median cut algorithm provided by quantize.js to cluster similar
|
||||||
|
* colors.
|
||||||
|
*
|
||||||
|
* BUGGY: Function does not always return the requested amount of colors. It can be +/- 2.
|
||||||
|
*/
|
||||||
|
function createPalette(sourceImage, colorCount){
|
||||||
|
|
||||||
|
var palette = [];
|
||||||
|
|
||||||
|
// Create custom CanvasImage object
|
||||||
|
var image = new CanvasImage(sourceImage),
|
||||||
|
imageData = image.getImageData(),
|
||||||
|
pixels = imageData.data,
|
||||||
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
|
// Store the RGB values in an array format suitable for quantize function
|
||||||
|
var pixelArray = [];
|
||||||
|
for (var i = 0; i < pixelCount; i++) {
|
||||||
|
// If pixel is mostly opaque
|
||||||
|
if(pixels[i*4+3] >= 125){
|
||||||
|
pixelArray.push( [pixels[i*4], pixels[i*4+1], pixels[i*4+2]]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send array to quantize function which clusters values
|
||||||
|
// using median cut algorithm
|
||||||
|
var cmap = MMCQ.quantize(pixelArray, colorCount);
|
||||||
|
var newPalette = cmap.palette();
|
||||||
|
|
||||||
|
return newPalette;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getAverageRGB(sourceImage)
|
||||||
|
* returns {r: num, g: num, b: num}
|
||||||
|
*
|
||||||
|
* Add up all pixels RGB values and return average.
|
||||||
|
* Tends to return muddy gray/brown color. Most likely, you'll be better
|
||||||
|
* off using getDominantColor() instead.
|
||||||
|
*/
|
||||||
|
function getAverageRGB(sourceImage) {
|
||||||
|
// Config
|
||||||
|
var sampleSize = 10;
|
||||||
|
|
||||||
|
// Create custom CanvasImage object
|
||||||
|
var image = new CanvasImage(sourceImage),
|
||||||
|
imageData = image.getImageData(),
|
||||||
|
pixels = imageData.data,
|
||||||
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
|
// Reset vars
|
||||||
|
var i = 0,
|
||||||
|
count = 0,
|
||||||
|
rgb = {r:0,g:0,b:0};
|
||||||
|
|
||||||
|
// Loop through every # pixels. (# is set in Config above via the blockSize var)
|
||||||
|
// Add all the red values together, repeat for blue and green.
|
||||||
|
// Last step, divide by the number of pixels checked to get average.
|
||||||
|
while ( (i += sampleSize * 4) < pixelCount ) {
|
||||||
|
// if pixel is mostly opaque
|
||||||
|
if(pixels[i+3] > 125){
|
||||||
|
++count;
|
||||||
|
rgb.r += pixels[i];
|
||||||
|
rgb.g += pixels[i+1];
|
||||||
|
rgb.b += pixels[i+2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb.r = Math.floor(rgb.r/count);
|
||||||
|
rgb.g = Math.floor(rgb.g/count);
|
||||||
|
rgb.b = Math.floor(rgb.b/count);
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* createAreaBasedPalette(sourceImage, colorCount)
|
||||||
|
* returns array[ {r: num, g: num, b: num}, {r: num, g: num, b: num}, ...]
|
||||||
|
*
|
||||||
|
* Break the image into sections. Loops through pixel RGBS in the section and average color.
|
||||||
|
* Tends to return muddy gray/brown color. You're most likely better off using createPalette().
|
||||||
|
*
|
||||||
|
* BUGGY: Function does not always return the requested amount of colors. It can be +/- 2.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function createAreaBasedPalette(sourceImage, colorCount){
|
||||||
|
|
||||||
|
var palette = [];
|
||||||
|
|
||||||
|
// Create custom CanvasImage object
|
||||||
|
var image = new CanvasImage(sourceImage),
|
||||||
|
imageData = image.getImageData(),
|
||||||
|
pixels = imageData.data,
|
||||||
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
|
|
||||||
|
// How big a pixel area does each palette color get
|
||||||
|
var rowCount = colCount = Math.round(Math.sqrt(colorCount)),
|
||||||
|
colWidth = Math.round(image.width / colCount),
|
||||||
|
rowHeight = Math.round(image.height / rowCount);
|
||||||
|
|
||||||
|
var count = offset = rowOffset = vertOffset = horizOffset = 0,
|
||||||
|
rgb = {r:0,g:0,b:0};
|
||||||
|
|
||||||
|
// Loop through pixels section by section.
|
||||||
|
// At the end of each section, push the average rgb color to palette array.
|
||||||
|
for(var i=0; i<rowCount; i++){
|
||||||
|
vertOffset = i * rowHeight * image.width * 4;
|
||||||
|
|
||||||
|
for(var j=0; j<colCount; j++){
|
||||||
|
horizOffset = j * colWidth * 4;
|
||||||
|
|
||||||
|
for( var k = 0; k < rowHeight; k++){
|
||||||
|
rowOffset = k * image.width * 4;
|
||||||
|
|
||||||
|
for( var l = 0; l < colWidth; l++){
|
||||||
|
offset = vertOffset + horizOffset + rowOffset + (l * 4);
|
||||||
|
rgb.r += pixels[offset];
|
||||||
|
rgb.g += pixels[offset+1];
|
||||||
|
rgb.b += pixels[offset+2];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
rgb.r = Math.floor(rgb.r/count);
|
||||||
|
rgb.g = Math.floor(rgb.g/count);
|
||||||
|
rgb.b = Math.floor(rgb.b/count);
|
||||||
|
palette.push(rgb);
|
||||||
|
|
||||||
|
// reset before next section
|
||||||
|
rgb = {r:0,g:0,b:0};
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
153
js/functions.js
153
js/functions.js
@@ -1,153 +0,0 @@
|
|||||||
|
|
||||||
function getAverageRGB(sourceImage) {
|
|
||||||
// Config
|
|
||||||
var sampleSize = 10;
|
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
|
||||||
var image = new CanvasImage(sourceImage),
|
|
||||||
imageData = image.getImageData(),
|
|
||||||
pixels = imageData.data,
|
|
||||||
pixelCount = image.getPixelCount();
|
|
||||||
|
|
||||||
// Reset vars
|
|
||||||
var i = 0,
|
|
||||||
count = 0,
|
|
||||||
rgb = {r:0,g:0,b:0};
|
|
||||||
|
|
||||||
// Loop through every # pixels. (# is set in Config above via the blockSize var)
|
|
||||||
// Add all the red values together, repeat for blue and green.
|
|
||||||
// Last step, divide by the number of pixels checked to get average.
|
|
||||||
while ( (i += sampleSize * 4) < pixelCount ) {
|
|
||||||
// if pixel is mostly opaque
|
|
||||||
if(pixels[i+3] > 125){
|
|
||||||
++count;
|
|
||||||
rgb.r += pixels[i];
|
|
||||||
rgb.g += pixels[i+1];
|
|
||||||
rgb.b += pixels[i+2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rgb.r = Math.floor(rgb.r/count);
|
|
||||||
rgb.g = Math.floor(rgb.g/count);
|
|
||||||
rgb.b = Math.floor(rgb.b/count);
|
|
||||||
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getDominantColor(sourceImage){
|
|
||||||
|
|
||||||
var palette = [];
|
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
|
||||||
var image = new CanvasImage(sourceImage),
|
|
||||||
imageData = image.getImageData(),
|
|
||||||
pixels = imageData.data,
|
|
||||||
pixelCount = image.getPixelCount();
|
|
||||||
|
|
||||||
var pixelArray = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < pixelCount; i++) {
|
|
||||||
// If pixel is mostly opaque
|
|
||||||
if(pixels[i*4+3] >= 125){
|
|
||||||
pixelArray.push( [pixels[i*4], pixels[i*4+1], pixels[i*4+2]]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var cmap = MMCQ.quantize(pixelArray, 5);
|
|
||||||
var newPalette = cmap.palette();
|
|
||||||
|
|
||||||
return {r: newPalette[0][0], g: newPalette[0][1], b: newPalette[0][2]};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function createAreaBasedPalette(sourceImage, colorCount){
|
|
||||||
|
|
||||||
var palette = [];
|
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
|
||||||
var image = new CanvasImage(sourceImage),
|
|
||||||
imageData = image.getImageData(),
|
|
||||||
pixels = imageData.data,
|
|
||||||
pixelCount = image.getPixelCount();
|
|
||||||
|
|
||||||
|
|
||||||
// How big a pixel area does each palette color get
|
|
||||||
var rowCount = colCount = Math.round(Math.sqrt(colorCount)),
|
|
||||||
colWidth = Math.round(image.width / colCount),
|
|
||||||
rowHeight = Math.round(image.height / rowCount);
|
|
||||||
|
|
||||||
var count = offset = rowOffset = vertOffset = horizOffset = 0,
|
|
||||||
rgb = {r:0,g:0,b:0};
|
|
||||||
|
|
||||||
for(var i=0; i<rowCount; i++){
|
|
||||||
vertOffset = i * rowHeight * image.width * 4;
|
|
||||||
|
|
||||||
for(var j=0; j<colCount; j++){
|
|
||||||
horizOffset = j * colWidth * 4;
|
|
||||||
|
|
||||||
for( var k = 0; k < rowHeight; k++){
|
|
||||||
rowOffset = k * image.width * 4;
|
|
||||||
|
|
||||||
for( var l = 0; l < colWidth; l++){
|
|
||||||
offset = vertOffset + horizOffset + rowOffset + (l * 4);
|
|
||||||
rgb.r += pixels[offset];
|
|
||||||
rgb.g += pixels[offset+1];
|
|
||||||
rgb.b += pixels[offset+2];
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
rgb.r = Math.floor(rgb.r/count);
|
|
||||||
rgb.g = Math.floor(rgb.g/count);
|
|
||||||
rgb.b = Math.floor(rgb.b/count);
|
|
||||||
palette.push(rgb);
|
|
||||||
|
|
||||||
// reset before next section
|
|
||||||
rgb = {r:0,g:0,b:0};
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return palette;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function createMedianCutPalette(sourceImage, colorCount){
|
|
||||||
|
|
||||||
var palette = [];
|
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
|
||||||
var image = new CanvasImage(sourceImage),
|
|
||||||
imageData = image.getImageData(),
|
|
||||||
pixels = imageData.data,
|
|
||||||
pixelCount = image.getPixelCount();
|
|
||||||
|
|
||||||
var pixelArray = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < pixelCount; i++) {
|
|
||||||
// If pixel is mostly opaque
|
|
||||||
if(pixels[i*4+3] >= 125){
|
|
||||||
pixelArray.push( [pixels[i*4], pixels[i*4+1], pixels[i*4+2]]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var cmap = MMCQ.quantize(pixelArray, colorCount);
|
|
||||||
var newPalette = cmap.palette();
|
|
||||||
|
|
||||||
return newPalette;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (var i = 0; i < pixelCount; i++) {
|
|
||||||
pixels[i*4] = pixels[i*4]; // Red
|
|
||||||
pixels[i*4+1] = pixels[i*4+1]; // Green
|
|
||||||
pixels[i*4+2] = pixels[i*4+2]; // Blue
|
|
||||||
};
|
|
||||||
|
|
||||||
image.clear();
|
|
||||||
imageData.data = pixels;
|
|
||||||
image.update(imageData);
|
|
||||||
*/
|
|
||||||
54
js/libs/jquery.imagesloaded.js
Normal file
54
js/libs/jquery.imagesloaded.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*!
|
||||||
|
* jQuery imagesLoaded plugin v1.0.4
|
||||||
|
* http://github.com/desandro/imagesloaded
|
||||||
|
*
|
||||||
|
* MIT License. by Paul Irish et al.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($, undefined) {
|
||||||
|
|
||||||
|
// $('#my-container').imagesLoaded(myFunction)
|
||||||
|
// or
|
||||||
|
// $('img').imagesLoaded(myFunction)
|
||||||
|
|
||||||
|
// execute a callback when all images have loaded.
|
||||||
|
// needed because .load() doesn't work on cached images
|
||||||
|
|
||||||
|
// callback function gets image collection as argument
|
||||||
|
// `this` is the container
|
||||||
|
|
||||||
|
$.fn.imagesLoaded = function( callback ) {
|
||||||
|
var $this = this,
|
||||||
|
$images = $this.find('img').add( $this.filter('img') ),
|
||||||
|
len = $images.length,
|
||||||
|
blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
|
||||||
|
|
||||||
|
function triggerCallback() {
|
||||||
|
callback.call( $this, $images );
|
||||||
|
}
|
||||||
|
|
||||||
|
function imgLoaded( event ) {
|
||||||
|
if ( --len <= 0 && event.target.src !== blank ){
|
||||||
|
setTimeout( triggerCallback );
|
||||||
|
$images.unbind( 'load error', imgLoaded );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !len ) {
|
||||||
|
triggerCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
$images.bind( 'load error', imgLoaded ).each( function() {
|
||||||
|
// cached images don't fire load sometimes, so we reset src.
|
||||||
|
if (this.complete || this.complete === undefined){
|
||||||
|
var src = this.src;
|
||||||
|
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
|
||||||
|
// data uri bypasses webkit log warning (thx doug jones)
|
||||||
|
this.src = blank;
|
||||||
|
this.src = src;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
};
|
||||||
|
})(jQuery);
|
||||||
419
js/libs/mustache.js
Normal file
419
js/libs/mustache.js
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
mustache.js — Logic-less templates in JavaScript
|
||||||
|
|
||||||
|
See http://mustache.github.com/ for more info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Mustache = function() {
|
||||||
|
var regexCache = {};
|
||||||
|
var Renderer = function() {};
|
||||||
|
|
||||||
|
Renderer.prototype = {
|
||||||
|
otag: "{{",
|
||||||
|
ctag: "}}",
|
||||||
|
pragmas: {},
|
||||||
|
buffer: [],
|
||||||
|
pragmas_implemented: {
|
||||||
|
"IMPLICIT-ITERATOR": true
|
||||||
|
},
|
||||||
|
context: {},
|
||||||
|
|
||||||
|
render: function(template, context, partials, in_recursion) {
|
||||||
|
// reset buffer & set context
|
||||||
|
if(!in_recursion) {
|
||||||
|
this.context = context;
|
||||||
|
this.buffer = []; // TODO: make this non-lazy
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail fast
|
||||||
|
if(!this.includes("", template)) {
|
||||||
|
if(in_recursion) {
|
||||||
|
return template;
|
||||||
|
} else {
|
||||||
|
this.send(template);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the pragmas together
|
||||||
|
template = this.render_pragmas(template);
|
||||||
|
|
||||||
|
// render the template
|
||||||
|
var html = this.render_section(template, context, partials);
|
||||||
|
|
||||||
|
// render_section did not find any sections, we still need to render the tags
|
||||||
|
if (html === false) {
|
||||||
|
html = this.render_tags(template, context, partials, in_recursion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_recursion) {
|
||||||
|
return html;
|
||||||
|
} else {
|
||||||
|
this.sendLines(html);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sends parsed lines
|
||||||
|
*/
|
||||||
|
send: function(line) {
|
||||||
|
if(line !== "") {
|
||||||
|
this.buffer.push(line);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
sendLines: function(text) {
|
||||||
|
if (text) {
|
||||||
|
var lines = text.split("\n");
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
this.send(lines[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Looks for %PRAGMAS
|
||||||
|
*/
|
||||||
|
render_pragmas: function(template) {
|
||||||
|
// no pragmas
|
||||||
|
if(!this.includes("%", template)) {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
var regex = this.getCachedRegex("render_pragmas", function(otag, ctag) {
|
||||||
|
return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g");
|
||||||
|
});
|
||||||
|
|
||||||
|
return template.replace(regex, function(match, pragma, options) {
|
||||||
|
if(!that.pragmas_implemented[pragma]) {
|
||||||
|
throw({message:
|
||||||
|
"This implementation of mustache doesn't understand the '" +
|
||||||
|
pragma + "' pragma"});
|
||||||
|
}
|
||||||
|
that.pragmas[pragma] = {};
|
||||||
|
if(options) {
|
||||||
|
var opts = options.split("=");
|
||||||
|
that.pragmas[pragma][opts[0]] = opts[1];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
// ignore unknown pragmas silently
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Tries to find a partial in the curent scope and render it
|
||||||
|
*/
|
||||||
|
render_partial: function(name, context, partials) {
|
||||||
|
name = this.trim(name);
|
||||||
|
if(!partials || partials[name] === undefined) {
|
||||||
|
throw({message: "unknown_partial '" + name + "'"});
|
||||||
|
}
|
||||||
|
if(typeof(context[name]) != "object") {
|
||||||
|
return this.render(partials[name], context, partials, true);
|
||||||
|
}
|
||||||
|
return this.render(partials[name], context[name], partials, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Renders inverted (^) and normal (#) sections
|
||||||
|
*/
|
||||||
|
render_section: function(template, context, partials) {
|
||||||
|
if(!this.includes("#", template) && !this.includes("^", template)) {
|
||||||
|
// did not render anything, there were no sections
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
var regex = this.getCachedRegex("render_section", function(otag, ctag) {
|
||||||
|
// This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder
|
||||||
|
return new RegExp(
|
||||||
|
"^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1)
|
||||||
|
|
||||||
|
otag + // {{
|
||||||
|
"(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3)
|
||||||
|
ctag + // }}
|
||||||
|
|
||||||
|
"\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped
|
||||||
|
|
||||||
|
otag + // {{
|
||||||
|
"\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag).
|
||||||
|
ctag + // }}
|
||||||
|
|
||||||
|
"\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped.
|
||||||
|
|
||||||
|
"g");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// for each {{#foo}}{{/foo}} section do...
|
||||||
|
return template.replace(regex, function(match, before, type, name, content, after) {
|
||||||
|
// before contains only tags, no sections
|
||||||
|
var renderedBefore = before ? that.render_tags(before, context, partials, true) : "",
|
||||||
|
|
||||||
|
// after may contain both sections and tags, so use full rendering function
|
||||||
|
renderedAfter = after ? that.render(after, context, partials, true) : "",
|
||||||
|
|
||||||
|
// will be computed below
|
||||||
|
renderedContent,
|
||||||
|
|
||||||
|
value = that.find(name, context);
|
||||||
|
|
||||||
|
if (type === "^") { // inverted section
|
||||||
|
if (!value || that.is_array(value) && value.length === 0) {
|
||||||
|
// false or empty list, render it
|
||||||
|
renderedContent = that.render(content, context, partials, true);
|
||||||
|
} else {
|
||||||
|
renderedContent = "";
|
||||||
|
}
|
||||||
|
} else if (type === "#") { // normal section
|
||||||
|
if (that.is_array(value)) { // Enumerable, Let's loop!
|
||||||
|
renderedContent = that.map(value, function(row) {
|
||||||
|
return that.render(content, that.create_context(row), partials, true);
|
||||||
|
}).join("");
|
||||||
|
} else if (that.is_object(value)) { // Object, Use it as subcontext!
|
||||||
|
renderedContent = that.render(content, that.create_context(value),
|
||||||
|
partials, true);
|
||||||
|
} else if (typeof value === "function") {
|
||||||
|
// higher order section
|
||||||
|
renderedContent = value.call(context, content, function(text) {
|
||||||
|
return that.render(text, context, partials, true);
|
||||||
|
});
|
||||||
|
} else if (value) { // boolean section
|
||||||
|
renderedContent = that.render(content, context, partials, true);
|
||||||
|
} else {
|
||||||
|
renderedContent = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderedBefore + renderedContent + renderedAfter;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Replace {{foo}} and friends with values from our view
|
||||||
|
*/
|
||||||
|
render_tags: function(template, context, partials, in_recursion) {
|
||||||
|
// tit for tat
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var new_regex = function() {
|
||||||
|
return that.getCachedRegex("render_tags", function(otag, ctag) {
|
||||||
|
return new RegExp(otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" + ctag + "+", "g");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var regex = new_regex();
|
||||||
|
var tag_replace_callback = function(match, operator, name) {
|
||||||
|
switch(operator) {
|
||||||
|
case "!": // ignore comments
|
||||||
|
return "";
|
||||||
|
case "=": // set new delimiters, rebuild the replace regexp
|
||||||
|
that.set_delimiters(name);
|
||||||
|
regex = new_regex();
|
||||||
|
return "";
|
||||||
|
case ">": // render partial
|
||||||
|
return that.render_partial(name, context, partials);
|
||||||
|
case "{": // the triple mustache is unescaped
|
||||||
|
return that.find(name, context);
|
||||||
|
default: // escape the value
|
||||||
|
return that.escape(that.find(name, context));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var lines = template.split("\n");
|
||||||
|
for(var i = 0; i < lines.length; i++) {
|
||||||
|
lines[i] = lines[i].replace(regex, tag_replace_callback, this);
|
||||||
|
if(!in_recursion) {
|
||||||
|
this.send(lines[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(in_recursion) {
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
set_delimiters: function(delimiters) {
|
||||||
|
var dels = delimiters.split(" ");
|
||||||
|
this.otag = this.escape_regex(dels[0]);
|
||||||
|
this.ctag = this.escape_regex(dels[1]);
|
||||||
|
},
|
||||||
|
|
||||||
|
escape_regex: function(text) {
|
||||||
|
// thank you Simon Willison
|
||||||
|
if(!arguments.callee.sRE) {
|
||||||
|
var specials = [
|
||||||
|
'/', '.', '*', '+', '?', '|',
|
||||||
|
'(', ')', '[', ']', '{', '}', '\\'
|
||||||
|
];
|
||||||
|
arguments.callee.sRE = new RegExp(
|
||||||
|
'(\\' + specials.join('|\\') + ')', 'g'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return text.replace(arguments.callee.sRE, '\\$1');
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
find `name` in current `context`. That is find me a value
|
||||||
|
from the view object
|
||||||
|
*/
|
||||||
|
find: function(name, context) {
|
||||||
|
name = this.trim(name);
|
||||||
|
|
||||||
|
// Checks whether a value is thruthy or false or 0
|
||||||
|
function is_kinda_truthy(bool) {
|
||||||
|
return bool === false || bool === 0 || bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value;
|
||||||
|
|
||||||
|
// check for dot notation eg. foo.bar
|
||||||
|
if(name.match(/([a-z_]+)\./ig)){
|
||||||
|
value = is_kinda_truthy(this.walk_context(name, context));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(is_kinda_truthy(context[name])) {
|
||||||
|
value = context[name];
|
||||||
|
} else if(is_kinda_truthy(this.context[name])) {
|
||||||
|
value = this.context[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof value === "function") {
|
||||||
|
return value.apply(context);
|
||||||
|
}
|
||||||
|
if(value !== undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
// silently ignore unkown variables
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
|
||||||
|
walk_context: function(name, context){
|
||||||
|
var path = name.split('.');
|
||||||
|
// if the var doesn't exist in current context, check the top level context
|
||||||
|
var value_context = (context[path[0]] != undefined) ? context : this.context;
|
||||||
|
var value = value_context[path.shift()];
|
||||||
|
while(value != undefined && path.length > 0){
|
||||||
|
value_context = value;
|
||||||
|
value = value[path.shift()];
|
||||||
|
}
|
||||||
|
// if the value is a function, call it, binding the correct context
|
||||||
|
if(typeof value === "function") {
|
||||||
|
return value.apply(value_context);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Utility methods
|
||||||
|
|
||||||
|
/* includes tag */
|
||||||
|
includes: function(needle, haystack) {
|
||||||
|
return haystack.indexOf(this.otag + needle) != -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Does away with nasty characters
|
||||||
|
*/
|
||||||
|
escape: function(s) {
|
||||||
|
s = String(s === null ? "" : s);
|
||||||
|
return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
|
||||||
|
switch(s) {
|
||||||
|
case "&": return "&";
|
||||||
|
case '"': return '"';
|
||||||
|
case "'": return ''';
|
||||||
|
case "<": return "<";
|
||||||
|
case ">": return ">";
|
||||||
|
default: return s;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// by @langalex, support for arrays of strings
|
||||||
|
create_context: function(_context) {
|
||||||
|
if(this.is_object(_context)) {
|
||||||
|
return _context;
|
||||||
|
} else {
|
||||||
|
var iterator = ".";
|
||||||
|
if(this.pragmas["IMPLICIT-ITERATOR"]) {
|
||||||
|
iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
|
||||||
|
}
|
||||||
|
var ctx = {};
|
||||||
|
ctx[iterator] = _context;
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
is_object: function(a) {
|
||||||
|
return a && typeof a == "object";
|
||||||
|
},
|
||||||
|
|
||||||
|
is_array: function(a) {
|
||||||
|
return Object.prototype.toString.call(a) === '[object Array]';
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets rid of leading and trailing whitespace
|
||||||
|
*/
|
||||||
|
trim: function(s) {
|
||||||
|
return s.replace(/^\s*|\s*$/g, "");
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Why, why, why? Because IE. Cry, cry cry.
|
||||||
|
*/
|
||||||
|
map: function(array, fn) {
|
||||||
|
if (typeof array.map == "function") {
|
||||||
|
return array.map(fn);
|
||||||
|
} else {
|
||||||
|
var r = [];
|
||||||
|
var l = array.length;
|
||||||
|
for(var i = 0; i < l; i++) {
|
||||||
|
r.push(fn(array[i]));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getCachedRegex: function(name, generator) {
|
||||||
|
var byOtag = regexCache[this.otag];
|
||||||
|
if (!byOtag) {
|
||||||
|
byOtag = regexCache[this.otag] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var byCtag = byOtag[this.ctag];
|
||||||
|
if (!byCtag) {
|
||||||
|
byCtag = byOtag[this.ctag] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var regex = byCtag[name];
|
||||||
|
if (!regex) {
|
||||||
|
regex = byCtag[name] = generator(this.otag, this.ctag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return({
|
||||||
|
name: "mustache.js",
|
||||||
|
version: "0.4.0-dev",
|
||||||
|
|
||||||
|
/*
|
||||||
|
Turns a template and view into HTML
|
||||||
|
*/
|
||||||
|
to_html: function(template, view, partials, send_fun) {
|
||||||
|
var renderer = new Renderer();
|
||||||
|
if(send_fun) {
|
||||||
|
renderer.send = send_fun;
|
||||||
|
}
|
||||||
|
renderer.render(template, view || {}, partials);
|
||||||
|
if(!send_fun) {
|
||||||
|
return renderer.buffer.join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}();
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
$color: #555
|
$color: #555
|
||||||
$headingColor: #222
|
$headingColor: #222
|
||||||
$altColor: scale-color($color, $lightness: 50%)
|
$altColor: scale-color($color, $lightness: 50%)
|
||||||
|
$lightGray: #eee
|
||||||
$blue: #09a1ec
|
$blue: #09a1ec
|
||||||
$orange: #e83
|
$orange: #e83
|
||||||
$green: #6bb445
|
$green: #6bb445
|
||||||
|
|||||||
146
sass/app.sass
146
sass/app.sass
@@ -1,11 +1,145 @@
|
|||||||
@import "base"
|
@import "base"
|
||||||
|
|
||||||
body
|
|
||||||
color: #444
|
|
||||||
font-family: 'lucida grande', sans-serif
|
|
||||||
line-height: 1.625em
|
/* =Global */
|
||||||
padding: 40px
|
|
||||||
|
|
||||||
|
body, input, textarea
|
||||||
|
margin: 40px
|
||||||
|
color: $color
|
||||||
|
font: 16px/1.625em 'Varela Round',"lucida grande",tahoma,sans-serif
|
||||||
|
font-weight: 400
|
||||||
|
-webkit-font-smoothing: antialiased
|
||||||
|
|
||||||
|
|
||||||
|
h1,h2,h3,h4,h5,h6
|
||||||
|
font-family: 'Terminal Dosis', 'lucida grande', tahoma, sans-serif
|
||||||
|
line-height: 1em
|
||||||
|
font-weight: 600
|
||||||
|
|
||||||
|
|
||||||
|
h1
|
||||||
|
font-size: 60px
|
||||||
|
|
||||||
|
h2
|
||||||
|
font-size: 24px
|
||||||
|
line-height: 1.2em
|
||||||
|
|
||||||
|
h3
|
||||||
|
font-size: 18px
|
||||||
|
letter-spacing: 0.1em
|
||||||
|
|
||||||
|
p
|
||||||
|
margin-bottom: 1.25em
|
||||||
|
|
||||||
|
|
||||||
|
strong
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Forms */
|
||||||
|
input[type=text],
|
||||||
|
input[type=password],
|
||||||
|
textarea
|
||||||
|
background: #fafafa
|
||||||
|
+box-shadow(inset 0 1px 1px rgba(0,0,0,0.1))
|
||||||
|
border: 1px solid #ddd
|
||||||
|
color: #888
|
||||||
|
+border-radius($radius)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
input[type=text]:focus,
|
||||||
|
textarea:focus
|
||||||
|
color: #373737
|
||||||
|
|
||||||
|
textarea
|
||||||
|
padding-left: 3px
|
||||||
|
width: 98%
|
||||||
|
|
||||||
|
input[type=text]
|
||||||
|
padding: 3px
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
a
|
||||||
|
color: $color
|
||||||
|
text-decoration: none
|
||||||
|
&:hover
|
||||||
|
color: $blue
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.button
|
||||||
|
text-transform: uppercase
|
||||||
|
font-family: 'Terminal Dosis', 'lucida grande', tahoma, sans-serif
|
||||||
|
font-weight: 700
|
||||||
|
letter-spacing: 0.1em
|
||||||
|
olor: #555
|
||||||
|
display: block
|
||||||
|
float: left
|
||||||
|
position: relative
|
||||||
|
line-height: 1
|
||||||
|
padding: .6em 1.5em .5em 1.5em
|
||||||
|
border: 1px solid transparent
|
||||||
|
+box-shadow( inset 0 2px 0 rgba(255, 255, 255, 0.1), 0 2px 5px 0 rgba(0,0,0, .25))
|
||||||
|
background-color: $lightGray
|
||||||
|
+border-radius($radius)
|
||||||
|
border: 1px solid scale-color($lightGray, $lightness: -10%)
|
||||||
|
margin-bottom: 6px
|
||||||
|
&:hover
|
||||||
|
background-color: scale-color($lightGray, $lightness: 20%)
|
||||||
|
&:active
|
||||||
|
+box-shadow( inset 0 2px 0 rgba(0, 0, 0, 0.1))
|
||||||
|
top: 2px
|
||||||
|
margin-bottom: 4px
|
||||||
|
border-bottom-width: 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Buttons with dark backgrounds */
|
||||||
|
.button.nav,
|
||||||
|
.button.warn,
|
||||||
|
.button.primary,
|
||||||
|
.nav-previous .button,
|
||||||
|
.nav-next .button
|
||||||
|
color: #fff
|
||||||
|
@include text-shadow(rgba(0,0,0, 0.2) 1px 1px 0)
|
||||||
|
|
||||||
|
|
||||||
|
.button.nav,
|
||||||
|
.nav-previous .button,
|
||||||
|
.nav-next .button
|
||||||
|
background-color: $blue
|
||||||
|
border-color: scale-color($blue, $lightness: -10%)
|
||||||
|
&:hover
|
||||||
|
background-color: scale-color($blue, $lightness: 20%)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.button.warn
|
||||||
|
background-color: $orange
|
||||||
|
border-color: scale-color($orange, $lightness: -10%)
|
||||||
|
&:hover
|
||||||
|
background-color: scale-color($orange, $lightness: 20%)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.button.primary
|
||||||
|
background-color: $green
|
||||||
|
border-color: $green
|
||||||
|
&:hover
|
||||||
|
background-color: scale-color($green, $lightness: 20%)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h1
|
h1
|
||||||
font-size: 36px
|
font-size: 36px
|
||||||
margin-bottom: .5em
|
margin-bottom: .5em
|
||||||
|
|||||||
Reference in New Issue
Block a user