Compare commits

..

16 Commits

Author SHA1 Message Date
Tom Burns
cb807e9484 Add extension to gemspec 2013-03-19 18:30:10 -04:00
Tom Burns
e53884ce08 Remove generated C file from repo 2013-03-19 18:30:09 -04:00
Tom Burns
78fe69259d Allow floats > 9 2013-03-19 18:30:09 -04:00
Tom Burns
afe8474a2b Remove extension Makefile 2013-03-19 18:30:09 -04:00
Tobias Lutke
e404f6d8e1 fixed but with single char identifiers 2013-03-19 18:30:09 -04:00
Tobias Lutke
8867d6a65f enable weird method endings 2013-03-19 18:30:09 -04:00
Tobias Lutke
141fa898d0 enabled hard mode 2013-03-19 18:30:09 -04:00
Tobias Lutke
58b04bae74 conquered parser_tests 2013-03-19 18:30:09 -04:00
Tobias Lütke
28737171f7 wip 2013-03-19 18:30:09 -04:00
Tobias Lütke
594b6da8c5 Initial checkin 2013-03-19 18:30:09 -04:00
Tobias Lutke
cf5fa5923d remove binaries 2013-03-19 18:30:09 -04:00
Tobias Lutke
7cc10b9abf various speedups 2013-03-19 18:30:09 -04:00
Tobias Lütke
20beec2de3 Convert parser to C99 2013-03-19 18:30:09 -04:00
Tobias Lutke
06486fd21d Implement naive recusrive descent
Ragel doesn't allow us to recurse so we simply
reinvoke the parser for each step.
2013-03-19 18:30:08 -04:00
Tobias Lütke
7dcf578898 Replace regexpes with Ragel grammer
context parsing was handrolled and pretty ad-hoc
this branch exists to explore parsing the context
through a defined fsm as produced by Ragel
2013-03-19 18:30:08 -04:00
Tobias Lutke
006e7475f4 fix benchmarks 2013-03-19 18:30:08 -04:00
107 changed files with 2555 additions and 2641 deletions

6
.gitignore vendored
View File

@@ -4,4 +4,8 @@
pkg pkg
*.rbc *.rbc
.rvmrc .rvmrc
.ruby-version *.o
*.bundle
ext/liquid/Makefile
ext/liquid/liquid_context.c

View File

@@ -1,26 +0,0 @@
# How to contribute
## Things we will merge
* Bugfixes
* Performance improvements
* Features which are likely to be useful to the majority of Liquid users
## Things we won't merge
* Code which introduces considerable performance degrations
* Code which touches performance critical parts of Liquid and comes without benchmarks
* Features which are not important for most people (we want to keep the core Liquid code small and tidy)
* Features which can easily be implemented on top of Liquid (for example as a custom filter or custom filesystem)
* Code which comes without tests
* Code which breaks existing tests
## Workflow
* Fork the Liquid repository
* Create a new branch in your fork
* If it makes sense, add tests for your code and run a performance benchmark
* Make sure all tests pass
* Create a pull request
* In the description, ping one of [@boourns](https://github.com/boourns), [@fw42](https://github.com/fw42), [@camilo](https://github.com/camilo), [@dylanahsmith](https://github.com/dylanahsmith), or [@arthurnn](https://github.com/arthurnn) and ask for a code review.

View File

@@ -1,52 +1,5 @@
# Liquid Version History # Liquid Version History
IMPORTANT: Liquid 2.6 is going to be the last version of Liquid which maintains explicit Ruby 1.8 compatability.
The following releases will only be tested against Ruby 1.9 and Ruby 2.0 and are likely to break on Ruby 1.8.
## 2.6.1 / 2014-01-10 / branch "2-6-stable"
Security fix, cherry-picked from master (4e14a65):
* Don't call to_sym when creating conditions for security reasons, see #273 [Bouke van der Bijl, bouk]
* Prevent arbitrary method invocation on condition objects, see #274 [Dylan Thacker-Smith, dylanahsmith]
## 2.6.0 / 2013-11-25
* ...
* Bugfix for #106: fix example servlet [gnowoel]
* Bugfix for #97: strip_html filter supports multi-line tags [Jo Liss, joliss]
* Bugfix for #114: strip_html filter supports style tags [James Allardice, jamesallardice]
* Bugfix for #117: 'now' support for date filter in Ruby 1.9 [Notre Dame Webgroup, ndwebgroup]
* Bugfix for #166: truncate filter on UTF-8 strings with Ruby 1.8 [Florian Weingarten, fw42]
* Bugfix for #204: 'raw' parsing bug [Florian Weingarten, fw42]
* Bugfix for #150: 'for' parsing bug [Peter Schröder, phoet]
* Bugfix for #126: Strip CRLF in strip_newline [Peter Schröder, phoet]
* Bugfix for #174, "can't convert Fixnum into String" for "replace" [wǒ_is神仙, jsw0528]
* Allow a Liquid::Drop to be passed into Template#render [Daniel Huckstep, darkhelmet]
* Resource limits [Florian Weingarten, fw42]
* Add reverse filter [Jay Strybis, unreal]
* Add utf-8 support
* Use array instead of Hash to keep the registered filters [Tasos Stathopoulos, astathopoulos]
* Cache tokenized partial templates [Tom Burns, boourns]
* Avoid warnings in Ruby 1.9.3 [Marcus Stollsteimer, stomar]
* Better documentation for 'include' tag (closes #163) [Peter Schröder, phoet]
* Use of BigDecimal on filters to have better precision (closes #155) [Arthur Nogueira Neves, arthurnn]
## 2.5.4 / 2013-11-11 / branch "2.5-stable"
* Fix "can't convert Fixnum into String" for "replace", see #173, [wǒ_is神仙, jsw0528]
## 2.5.3 / 2013-10-09
* #232, #234, #237: Fix map filter bugs [Florian Weingarten, fw42]
## 2.5.2 / 2013-09-03 / deleted
Yanked from rubygems, as it contained too many changes that broke compatibility. Those changes will be on following major releases.
## 2.5.1 / 2013-07-24
* #230: Fix security issue with map filter, Use invoke_drop in map filter [Florian Weingarten, fw42]
## 2.5.0 / 2013-03-06 ## 2.5.0 / 2013-03-06
* Prevent Object methods from being called on drops * Prevent Object methods from being called on drops
@@ -55,7 +8,6 @@ Yanked from rubygems, as it contained too many changes that broke compatibility.
* Fix filter parser for args without space separators * Fix filter parser for args without space separators
* Add support for filter keyword arguments * Add support for filter keyword arguments
## 2.4.0 / 2012-08-03 ## 2.4.0 / 2012-08-03
* Performance improvements * Performance improvements

View File

@@ -1,11 +1,5 @@
# Liquid template engine # Liquid template engine
* [Contributing guidelines](CONTRIBUTING.md)
* [Version history](History.md)
* [Liquid documentation from Shopify](http://docs.shopify.com/themes/liquid-basics)
* [Liquid Wiki from Shopify](http://wiki.shopify.com/Liquid)
* [Website](http://liquidmarkup.org/)
## Introduction ## Introduction
Liquid is a template engine which was written with very specific requirements: Liquid is a template engine which was written with very specific requirements:

View File

@@ -1,30 +1,64 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'rake' require 'rake'
require 'rake/clean'
require 'fileutils'
require 'rake/testtask' require 'rake/testtask'
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__) require 'rubygems/package_task'
require "liquid/version"
task :default => 'test' task :default => [:compile, :test]
Rake::TestTask.new(:test) do |t| task :gen do
sh "leg -oext/liquid/liquid_context.c ext/liquid/liquid_context.leg"
end
task :compile => [:gen, :liquid_ext]
extension = "liquid_ext"
ext = "ext/liquid"
ext_so = "#{ext}/#{extension}.#{RbConfig::CONFIG['DLEXT']}"
ext_files = FileList[
"#{ext}/*.c",
"#{ext}/*.h",
"#{ext}/*.leg",
"#{ext}/extconf.rb",
"#{ext}/Makefile",
"lib"
]
task "lib" do
directory "lib"
end
desc "Builds just the #{extension} extension"
task extension.to_sym => [:gen, "#{ext}/Makefile", ext_so ]
file "#{ext}/Makefile" => ["#{ext}/extconf.rb"] do
Dir.chdir(ext) do ruby "extconf.rb" end
end
file ext_so => ext_files do
Dir.chdir(ext) do
sh "make"
end
cp ext_so, "lib"
end
Rake::TestTask.new(:test => [:gen, 'liquid_ext']) do |t|
t.libs << '.' << 'lib' << 'test' t.libs << '.' << 'lib' << 'test'
t.test_files = FileList['test/liquid/**/*_test.rb'] t.test_files = FileList['test/liquid/**/*_test.rb']
t.verbose = false t.verbose = false
end end
task :gem => :build gemspec = eval(File.read('liquid.gemspec'))
task :build do Gem::PackageTask.new(gemspec) do |pkg|
system "gem build liquid.gemspec" pkg.gem_spec = gemspec
end end
task :install => :build do desc "Build the gem and release it to rubygems.org"
system "gem install liquid-#{Liquid::VERSION}.gem" task :release => :gem do
end sh "gem push pkg/liquid-#{gemspec.version}.gem"
task :release => :build do
system "git tag -a v#{Liquid::VERSION} -m 'Tagging #{Liquid::VERSION}'"
system "git push --tags"
system "gem push liquid-#{Liquid::VERSION}.gem"
system "rm liquid-#{Liquid::VERSION}.gem"
end end
namespace :benchmark do namespace :benchmark do
@@ -46,7 +80,7 @@ namespace :profile do
desc "Run KCacheGrind" desc "Run KCacheGrind"
task :grind => :run do task :grind => :run do
system "qcachegrind /tmp/liquid.rubyprof_calltreeprinter.txt" system "qcachegrind /tmp//callgrind.liquid.txt"
end end
end end

View File

@@ -23,7 +23,11 @@ class Servlet < LiquidServlet
end end
def products def products
{ 'products' => products_list, 'description' => description, 'section' => 'Snowboards', 'cool_products' => true} { 'products' => products_list, 'section' => 'Snowboards', 'cool_products' => true}
end
def description
"List of Products ~ This is a list of products with price and description."
end end
private private
@@ -34,8 +38,4 @@ class Servlet < LiquidServlet
{'name' => 'Arbor Diamond', 'price' => 59900, 'description' => 'the *arbor diamond* is a made up product because im obsessed with arbor and have no creativity'}] {'name' => 'Arbor Diamond', 'price' => 59900, 'description' => 'the *arbor diamond* is a made up product because im obsessed with arbor and have no creativity'}]
end end
def description
"List of Products ~ This is a list of products with price and description."
end
end end

View File

@@ -1,27 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en-us" /> <meta http-equiv="Content-Language" content="en-us" />
<title>products</title> <title>products</title>
<meta name="ROBOTS" content="ALL" /> <meta name="ROBOTS" content="ALL" />
<meta http-equiv="imagetoolbar" content="no" /> <meta http-equiv="imagetoolbar" content="no" />
<meta name="MSSmartTagsPreventParsing" content="true" /> <meta name="MSSmartTagsPreventParsing" content="true" />
<meta name="Copyright" content="(c) 2005 Copyright content: Copyright design: Tobias Luetke" /> <meta name="Copyright" content="(c) 2005 Copyright content: Copyright design: Tobias Luetke" />
<!-- (c) Copyright 2005 by Tobias Luetke All Rights Reserved. --> <!-- (c) Copyright 2005 by Tobias Luetke All Rights Reserved. -->
</head> </head>
<body> <body>
<h1>{{ description | split: '~' | first }}</h1> <h1>{{ description | split: '~' | first }}</h1>
<h2>{{ description | split: '~' | last }}</h2> <h2>{{ description | split: '~' | last }}</h2>
<h2>There are currently {{products | count}} products in the {{section}} catalog</h2> <h2>There are currently {{products | count}} products in the {{section}} catalog</h2>
{% if cool_products %} {% if cool_products %}
Cool products :) Cool products :)
@@ -45,5 +45,5 @@
</ul> </ul>
</body> </body>
</html> </html>

6
ext/liquid/extconf.rb Normal file
View File

@@ -0,0 +1,6 @@
require 'mkmf'
dir_config("liquid_ext")
have_library("c", "main")
create_makefile("liquid_ext")

View File

@@ -0,0 +1,98 @@
%{
//uncomment to get more debug instrumentation
//
//#define YY_DEBUG
#include <ruby.h>
#define EMIT(sym, data) \
rb_ary_push(ctx->rb_tokens, rb_ary_new3(2, ID2SYM(rb_intern(sym)), data));
#define yy_rb_str rb_str_new(yytext, yyleng)
#define YYSTYPE VALUE
#define YY_CTX_LOCAL
#define YY_CTX_MEMBERS VALUE rb_tokens; char *p; int p_len;
#define YY_INPUT(buf, result, max_size) { \
result = ctx->p_len; \
if (result>0 || EOF == ctx->p[0]) { \
if (max_size < result) { result = max_size; } \
strncpy(buf, ctx->p, result); \
buf[result] = '\0'; \
yyprintf((stderr, "\nREFILLING %d chars now:<%s>", result, buf)); \
ctx->p += result; ctx->p_len -= result; \
yyprintf((stderr, "\nREFILLING DONE size left: %d <%s>", ctx->p_len, ctx->p)); \
} \
}
%}
grammar = primary
| entity
| range
| hash { EMIT("lookup", Qnil); }
;
hash = '[' (primary|entity) ']';
primary = var:const { EMIT("id", var); }
| var:string { EMIT("id", var); }
| var:numeric { EMIT("id", var); }
;
accessors = hash { EMIT("call", Qnil); }
| '.first' { EMIT("buildin", rb_str_new2("first")); }
| '.last' { EMIT("buildin", rb_str_new2("last")); }
| '.size' { EMIT("buildin", rb_str_new2("size")); }
| '.' <identifier> { EMIT("id", yy_rb_str); EMIT("call", Qnil); }
;
entity = <identifier> { EMIT("id", yy_rb_str); EMIT("lookup", Qnil); }
accessors*
;
rangelet = var:integer { EMIT("id", var); }
| entity
;
range = '(' rangelet '..' rangelet ')' { EMIT("range", Qnil); }
string = ['] < ( !['] . )* > ['] { $$ = yy_rb_str; }
| ["] < ( !["] . )* > ["] { $$ = yy_rb_str; }
;
numeric = float
| integer
;
float = <'-'? digit+'.'digit+> { $$ = rb_funcall(rb_cObject, rb_intern("Float"), 1, yy_rb_str); }
integer = <'-'? digit+> { $$ = rb_funcall(rb_cObject, rb_intern("Integer"), 1, yy_rb_str); }
const = "true" { $$ = Qtrue; }
| 'false' { $$ = Qfalse; }
| 'nil' { $$ = Qnil; }
| 'null' { $$ = Qnil; }
;
digit = [0-9];
identifier = [a-zA-Z][a-zA-Z0-9_\-]*[?!]?;
%%
VALUE liquid_context_parse_impl(VALUE self, VALUE text) {
char *p;
int len;
yycontext ctx;
memset(&ctx, 0, sizeof(yycontext));
ctx.p = RSTRING_PTR(text);
ctx.p_len = (int) RSTRING_LEN(text);
ctx.rb_tokens = rb_ary_new();
yyparse(&ctx);
return ctx.rb_tokens;
}

13
ext/liquid/liquid_ext.c Normal file
View File

@@ -0,0 +1,13 @@
#include <ruby.h>
static VALUE rb_Liquid;
static VALUE rb_Parser;
VALUE liquid_context_parse_impl(VALUE text);
void Init_liquid_ext()
{
rb_Liquid = rb_define_module("Liquid");
rb_Parser = rb_define_class_under(rb_Liquid, "Parser", rb_cObject);
rb_define_singleton_method(rb_Parser, "parse", liquid_context_parse_impl, 1);
}

View File

@@ -45,7 +45,6 @@ module Liquid
VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o VariableParser = /\[[^\]]+\]|#{VariableSegment}+\??/o
end end
require "liquid/version"
require 'liquid/drop' require 'liquid/drop'
require 'liquid/extensions' require 'liquid/extensions'
require 'liquid/errors' require 'liquid/errors'
@@ -63,6 +62,7 @@ require 'liquid/standardfilters'
require 'liquid/condition' require 'liquid/condition'
require 'liquid/module_ex' require 'liquid/module_ex'
require 'liquid/utils' require 'liquid/utils'
require 'liquid_ext'
# Load all the tags of the standard library # Load all the tags of the standard library
# #

View File

@@ -16,7 +16,7 @@ module Liquid
when IsTag when IsTag
if token =~ FullToken if token =~ FullToken
# if we found the proper block delimiter just end parsing here and let the outer block # if we found the proper block delimitor just end parsing here and let the outer block
# proceed # proceed
if block_delimiter == $1 if block_delimiter == $1
end_tag end_tag
@@ -43,8 +43,8 @@ module Liquid
end end
end end
# Make sure that it's ok to end parsing in the current block. # Make sure that its ok to end parsing in the current block.
# Effectively this method will throw an exception unless the current block is # Effectively this method will throw and exception unless the current block is
# of type Document # of type Document
assert_missing_delimitation! assert_missing_delimitation!
end end
@@ -90,9 +90,6 @@ module Liquid
def render_all(list, context) def render_all(list, context)
output = [] output = []
context.resource_limits[:render_length_current] = 0
context.resource_limits[:render_score_current] += list.length
list.each do |token| list.each do |token|
# Break out if we have any unhanded interrupts. # Break out if we have any unhanded interrupts.
break if context.has_interrupt? break if context.has_interrupt?
@@ -106,21 +103,13 @@ module Liquid
break break
end end
token_output = (token.respond_to?(:render) ? token.render(context) : token) output << (token.respond_to?(:render) ? token.render(context) : token)
context.resource_limits[:render_length_current] += (token_output.respond_to?(:length) ? token_output.length : 1)
if context.resource_limits_reached?
context.resource_limits[:reached] = true
raise MemoryError.new("Memory limits exceeded")
end
output << token_output
rescue MemoryError => e
raise e
rescue ::StandardError => e rescue ::StandardError => e
output << (context.handle_error(e)) output << (context.handle_error(e))
end end
end end
output.join output
end end
end end
end end

View File

@@ -1,5 +1,6 @@
module Liquid module Liquid
# Context keeps the variable stack and resolves variables, as well as keywords # Context keeps the variable stack and resolves variables, as well as keywords
# #
# context['variable'] = 'testing' # context['variable'] = 'testing'
@@ -13,26 +14,19 @@ module Liquid
# #
# context['bob'] #=> nil class Context # context['bob'] #=> nil class Context
class Context class Context
attr_reader :scopes, :errors, :registers, :environments, :resource_limits attr_reader :scopes, :errors, :registers, :environments
def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false, resource_limits = {}) def initialize(environments = {}, outer_scope = {}, registers = {}, rethrow_errors = false)
@environments = [environments].flatten @environments = [environments].flatten
@scopes = [(outer_scope || {})] @scopes = [(outer_scope || {})]
@registers = registers @registers = registers
@errors = [] @errors = []
@rethrow_errors = rethrow_errors @rethrow_errors = rethrow_errors
@resource_limits = (resource_limits || {}).merge!({ :render_score_current => 0, :assign_score_current => 0 })
squash_instance_assigns_with_environments squash_instance_assigns_with_environments
@interrupts = [] @interrupts = []
end end
def resource_limits_reached?
(@resource_limits[:render_length_limit] && @resource_limits[:render_length_current] > @resource_limits[:render_length_limit]) ||
(@resource_limits[:render_score_limit] && @resource_limits[:render_score_current] > @resource_limits[:render_score_limit] ) ||
(@resource_limits[:assign_score_limit] && @resource_limits[:assign_score_current] > @resource_limits[:assign_score_limit] )
end
def strainer def strainer
@strainer ||= Strainer.create(self) @strainer ||= Strainer.create(self)
end end
@@ -53,7 +47,7 @@ module Liquid
# are there any not handled interrupts? # are there any not handled interrupts?
def has_interrupt? def has_interrupt?
@interrupts.any? !@interrupts.empty?
end end
# push an interrupt to the stack. this interrupt is considered not handled. # push an interrupt to the stack. this interrupt is considered not handled.
@@ -118,61 +112,95 @@ module Liquid
@scopes[0] = {} @scopes[0] = {}
end end
# Look up variable, either resolve directly after considering the name. We can directly handle
# Strings, digits, floats and booleans (true,false).
# If no match is made we lookup the variable in the current scope and
# later move up to the parent blocks to see if we can resolve the variable somewhere up the tree.
# Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions
#
# Example:
# products == empty #=> products.empty?
def resolve(key)
case key
when nil, ""
return nil
when "blank"
return :blank?
when "empty"
return :empty?
end
result = Parser.parse(key)
stack = []
result.each do |(sym, value)|
case sym
when :id
stack.push value
when :lookup
left = stack.pop
value = find_variable(left)
stack.push(harden(value))
when :range
right = stack.pop.to_i
left = stack.pop.to_i
stack.push (left..right)
when :buildin
left = stack.pop
value = invoke_buildin(left, value)
stack.push(harden(value))
when :call
left = stack.pop
right = stack.pop
value = lookup_and_evaluate(right, left)
stack.push(harden(value))
else
raise "unknown #{sym}"
end
end
return stack.first
end
# Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt> # Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
def []=(key, value) def []=(key, value)
@scopes[0][key] = value @scopes[0][key] = value
end end
def [](key)
resolve(key)
end
def has_key?(key) def has_key?(key)
resolve(key) != nil resolve(key) != nil
end end
private alias_method :[], :resolve
LITERALS = {
nil => nil, 'nil' => nil, 'null' => nil, '' => nil,
'true' => true,
'false' => false,
'blank' => :blank?,
'empty' => :empty?
}
# Look up variable, either resolve directly after considering the name. We can directly handle private
# Strings, digits, floats and booleans (true,false).
# If no match is made we lookup the variable in the current scope and def invoke_buildin(obj, key)
# later move up to the parent blocks to see if we can resolve the variable somewhere up the tree. # as weird as this is, liquid unit tests demand that we prioritize hash lookups
# Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions # to buildins. So if we got a hash and it has a :first element we need to call that
# # instead of sending the first message...
# Example:
# products == empty #=> products.empty? if obj.respond_to?(:has_key?) && obj.has_key?(key)
def resolve(key) return lookup_and_evaluate(obj, key)
if LITERALS.key?(key) end
LITERALS[key]
if obj.respond_to?(key)
return obj.send(key)
else else
case key return nil
when /^'(.*)'$/ # Single quoted strings
$1
when /^"(.*)"$/ # Double quoted strings
$1
when /^(-?\d+)$/ # Integer and floats
$1.to_i
when /^\((\S+)\.\.(\S+)\)$/ # Ranges
(resolve($1).to_i..resolve($2).to_i)
when /^(-?\d[\d\.]+)$/ # Floats
$1.to_f
else
variable(key)
end
end end
end end
# Fetches an object starting at the local scope and then moving up the hierachy # Fetches an object starting at the local scope and then moving up the hierachy
def find_variable(key) def find_variable(key)
scope = @scopes.find { |s| s.has_key?(key) } scope = @scopes.find { |s| s.has_key?(key) }
variable = nil
if scope.nil? if scope.nil?
@environments.each do |e| @environments.each do |e|
@@ -186,71 +214,34 @@ module Liquid
scope ||= @environments.last || @scopes.last scope ||= @environments.last || @scopes.last
variable ||= lookup_and_evaluate(scope, key) variable ||= lookup_and_evaluate(scope, key)
variable = variable.to_liquid
variable.context = self if variable.respond_to?(:context=)
return variable return variable
end end
# Resolves namespaced queries gracefully.
#
# Example
# @context['hash'] = {"name" => 'tobi'}
# assert_equal 'tobi', @context['hash.name']
# assert_equal 'tobi', @context['hash["name"]']
def variable(markup)
parts = markup.scan(VariableParser)
square_bracketed = /^\[(.*)\]$/
first_part = parts.shift
if first_part =~ square_bracketed
first_part = resolve($1)
end
if object = find_variable(first_part)
parts.each do |part|
part = resolve($1) if part_resolved = (part =~ square_bracketed)
# If object is a hash- or array-like object we look for the
# presence of the key and if its available we return it
if object.respond_to?(:[]) and
((object.respond_to?(:has_key?) and object.has_key?(part)) or
(object.respond_to?(:fetch) and part.is_a?(Integer)))
# if its a proc we will replace the entry with the proc
res = lookup_and_evaluate(object, part)
object = res.to_liquid
# Some special cases. If the part wasn't in square brackets and
# no key with the same name was found we interpret following calls
# as commands and call them on the current object
elsif !part_resolved and object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
object = object.send(part.intern).to_liquid
# No key was present with the desired value and it wasn't one of the directly supported
# keywords either. The only thing we got left is to return nil
else
return nil
end
# If we are dealing with a drop here we have to
object.context = self if object.respond_to?(:context=)
end
end
object
end # variable
def lookup_and_evaluate(obj, key) def lookup_and_evaluate(obj, key)
if (value = obj[key]).is_a?(Proc) && obj.respond_to?(:[]=) return nil unless obj.respond_to?(:[])
obj[key] = (value.arity == 0) ? value.call : value.call(self)
else if obj.is_a?(Array)
value return nil unless key.is_a?(Integer)
end end
end # lookup_and_evaluate
value = obj[key]
if value.is_a?(Proc)
# call the proc
value = (value.arity == 0) ? value.call : value.call(self)
# memozie if possible
obj[key] = value if obj.respond_to?(:[]=)
end
value
end
def harden(value)
value = value.to_liquid
value.context = self if value.respond_to?(:context=)
return value
end
def squash_instance_assigns_with_environments def squash_instance_assigns_with_environments
@scopes.last.each_key do |k| @scopes.last.each_key do |k|
@@ -262,6 +253,7 @@ module Liquid
end end
end end
end # squash_instance_assigns_with_environments end # squash_instance_assigns_with_environments
end # Context end # Context
end # Liquid end # Liquid

View File

@@ -5,7 +5,7 @@ module Liquid
parse(tokens) parse(tokens)
end end
# There isn't a real delimiter # There isn't a real delimter
def block_delimiter def block_delimiter
[] []
end end

View File

@@ -54,7 +54,7 @@ module Liquid
# Check for method existence without invoking respond_to?, which creates symbols # Check for method existence without invoking respond_to?, which creates symbols
def self.invokable?(method_name) def self.invokable?(method_name)
@invokable_methods ||= Set.new(["to_liquid"] + (public_instance_methods - Liquid::Drop.public_instance_methods).map(&:to_s)) @invokable_methods ||= Set.new((public_instance_methods - Liquid::Drop.public_instance_methods).map(&:to_s))
@invokable_methods.include?(method_name.to_s) @invokable_methods.include?(method_name.to_s)
end end
end end

View File

@@ -8,5 +8,4 @@ module Liquid
class StandardError < Error; end class StandardError < Error; end
class SyntaxError < Error; end class SyntaxError < Error; end
class StackLevelError < Error; end class StackLevelError < Error; end
class MemoryError < Error; end
end end

View File

@@ -1,5 +1,5 @@
module Liquid module Liquid
# A Liquid file system is a way to let your templates retrieve other templates for use with the include tag. # A Liquid file system is way to let your templates retrieve other templates for use with the include tag.
# #
# You can implement subclasses that retrieve templates from the database, from the file system using a different # You can implement subclasses that retrieve templates from the database, from the file system using a different
# path structure, you can provide them as hard-coded inline strings, or any manner that you see fit. # path structure, you can provide them as hard-coded inline strings, or any manner that you see fit.

View File

@@ -6,6 +6,8 @@ module Liquid
if markup =~ Syntax if markup =~ Syntax
@variable_name = $1 @variable_name = $1
@collection_name = $2 @collection_name = $2
@idx_i = "#{$1}-#{$2}-i"
@idx_col = "#{$1}-#{$2}-c"
@attributes = {} @attributes = {}
markup.scan(TagAttributes) do |key, value| markup.scan(TagAttributes) do |key, value|
@attributes[key] = value @attributes[key] = value
@@ -18,6 +20,8 @@ module Liquid
end end
def render(context) def render(context)
context.registers[:tablerowloop] ||= Hash.new(0)
collection = context[@collection_name] or return '' collection = context[@collection_name] or return ''
from = @attributes['offset'] ? context[@attributes['offset']].to_i : 0 from = @attributes['offset'] ? context[@attributes['offset']].to_i : 0
@@ -32,31 +36,21 @@ module Liquid
row = 1 row = 1
col = 0 col = 0
result = "<tr class=\"row1\">\n" result = ["<tr class=\"row1\">\n"]
context.stack do context.stack do
context.registers[:tablerowloop][@idx]
context['tablerowloop'] = lambda { Tablerowloop.new(@idx_i, @idx_col, length) }
collection.each_with_index do |item, index| collection.each_with_index do |item, index|
context.registers[:tablerowloop][@idx_i] = index
context.registers[:tablerowloop][@idx_col] = col
context[@variable_name] = item context[@variable_name] = item
context['tablerowloop'] = {
'length' => length,
'index' => index + 1,
'index0' => index,
'col' => col + 1,
'col0' => col,
'rindex' => length - index,
'rindex0' => length - index - 1,
'first' => (index == 0),
'last' => (index == length - 1),
'col_first' => (col == 0),
'col_last' => (col == cols - 1)
}
col += 1 col += 1
result << "<td class=\"col#{col}\">" << render_all(@nodelist, context) << '</td>' result << "<td class=\"col#{col}\">" << render_all(@nodelist, context) << '</td>'
if col == cols and (index != length - 1) if col == cols and not (index == length - 1)
col = 0 col = 0
row += 1 row += 1
result << "</tr>\n<tr class=\"row#{row}\">" result << "</tr>\n<tr class=\"row#{row}\">"
@@ -67,6 +61,58 @@ module Liquid
result << "</tr>\n" result << "</tr>\n"
result result
end end
private
class Tablerowloop < Liquid::Drop
attr_accessor :length
def initialize(idx_i, idx_col, length)
@idx_i, @idx_col, @length = idx_i, idx_col, length
end
def index
@context.registers[:tablerowloop][@idx_i] + 1
end
def index0
@context.registers[:tablerowloop][@idx_i]
end
def rindex
length - @context.registers[:tablerowloop][@idx_i]
end
def rindex0
length - @context.registers[:tablerowloop][@idx_i] - 1
end
def first
(@context.registers[:tablerowloop][@idx_i] == 0)
end
def last
(@context.registers[:tablerowloop][@idx_i] == length - 1)
end
def col
@context.registers[:tablerowloop][@idx_col] + 1
end
def col0
@context.registers[:tablerowloop][@idx_col]
end
def col_first
(@context.registers[:tablerowloop][@idx_col] == 0)
end
def col_last
(@context.registers[:tablerowloop][@idx_col] == cols - 1)
end
end
end end
Template.register_tag('tablerow', TableRow) Template.register_tag('tablerow', TableRow)

View File

@@ -2,7 +2,7 @@
# This library is free software. It may be used, redistributed and/or modified # This library is free software. It may be used, redistributed and/or modified
# under the same terms as Ruby itself # under the same terms as Ruby itself
# #
# This extension is used in order to expose the object of the implementing class # This extension is usesd in order to expose the object of the implementing class
# to liquid as it were a Drop. It also limits the liquid-callable methods of the instance # to liquid as it were a Drop. It also limits the liquid-callable methods of the instance
# to the allowed method passed with the liquid_methods call # to the allowed method passed with the liquid_methods call
# Example: # Example:

View File

@@ -1,5 +1,4 @@
require 'cgi' require 'cgi'
require 'bigdecimal'
module Liquid module Liquid
@@ -11,12 +10,12 @@ module Liquid
input.respond_to?(:size) ? input.size : 0 input.respond_to?(:size) ? input.size : 0
end end
# convert an input string to DOWNCASE # convert a input string to DOWNCASE
def downcase(input) def downcase(input)
input.to_s.downcase input.to_s.downcase
end end
# convert an input string to UPCASE # convert a input string to UPCASE
def upcase(input) def upcase(input)
input.to_s.upcase input.to_s.upcase
end end
@@ -43,8 +42,7 @@ module Liquid
if input.nil? then return end if input.nil? then return end
l = length.to_i - truncate_string.length l = length.to_i - truncate_string.length
l = 0 if l < 0 l = 0 if l < 0
truncated = RUBY_VERSION[0,3] == "1.8" ? input.scan(/./mu)[0...l].to_s : input[0...l] input.length > length.to_i ? input[0...l] + truncate_string : input
input.length > length.to_i ? truncated + truncate_string : input
end end
def truncatewords(input, words = 15, truncate_string = "...") def truncatewords(input, words = 15, truncate_string = "...")
@@ -65,14 +63,15 @@ module Liquid
end end
def strip_html(input) def strip_html(input)
input.to_s.gsub(/<script.*?<\/script>/m, '').gsub(/<!--.*?-->/m, '').gsub(/<style.*?<\/style>/m, '').gsub(/<.*?>/m, '') input.to_s.gsub(/<script.*?<\/script>/, '').gsub(/<!--.*?-->/, '').gsub(/<.*?>/, '')
end end
# Remove all newlines from the string # Remove all newlines from the string
def strip_newlines(input) def strip_newlines(input)
input.to_s.gsub(/\r?\n/, '') input.to_s.gsub(/\n/, '')
end end
# Join elements of the array with certain character between them # Join elements of the array with certain character between them
def join(input, glue = ' ') def join(input, glue = ' ')
[input].flatten.join(glue) [input].flatten.join(glue)
@@ -91,35 +90,24 @@ module Liquid
end end
end end
# Reverse the elements of an array
def reverse(input)
ary = [input].flatten
ary.reverse
end
# map/collect on a given property # map/collect on a given property
def map(input, property) def map(input, property)
ary = [input].flatten ary = [input].flatten
ary.map do |e| if ary.first.respond_to?('[]') and !ary.first[property].nil?
e = e.call if e.is_a?(Proc) ary.map {|e| e[property] }
e = e.to_liquid if e.respond_to?(:to_liquid) elsif ary.first.respond_to?(property)
ary.map {|e| e.send(property) }
if property == "to_liquid"
e
elsif e.respond_to?(:[])
e[property]
end
end end
end end
# Replace occurrences of a string with another # Replace occurrences of a string with another
def replace(input, string, replacement = '') def replace(input, string, replacement = '')
input.to_s.gsub(string, replacement.to_s) input.to_s.gsub(string, replacement)
end end
# Replace the first occurrences of a string with another # Replace the first occurrences of a string with another
def replace_first(input, string, replacement = '') def replace_first(input, string, replacement = '')
input.to_s.sub(string, replacement.to_s) input.to_s.sub(string, replacement)
end end
# remove a substring # remove a substring
@@ -185,23 +173,14 @@ module Liquid
input = Time.at(input.to_i) input = Time.at(input.to_i)
end end
date = if input.is_a?(String) date = input.is_a?(String) ? Time.parse(input) : input
case input.downcase
when 'now', 'today'
Time.now
else
Time.parse(input)
end
else
input
end
if date.respond_to?(:strftime) if date.respond_to?(:strftime)
date.strftime(format.to_s) date.strftime(format.to_s)
else else
input input
end end
rescue rescue => e
input input
end end
@@ -225,47 +204,41 @@ module Liquid
# addition # addition
def plus(input, operand) def plus(input, operand)
apply_operation(input, operand, :+) to_number(input) + to_number(operand)
end end
# subtraction # subtraction
def minus(input, operand) def minus(input, operand)
apply_operation(input, operand, :-) to_number(input) - to_number(operand)
end end
# multiplication # multiplication
def times(input, operand) def times(input, operand)
apply_operation(input, operand, :*) to_number(input) * to_number(operand)
end end
# division # division
def divided_by(input, operand) def divided_by(input, operand)
apply_operation(input, operand, :/) to_number(input) / to_number(operand)
end end
def modulo(input, operand) def modulo(input, operand)
apply_operation(input, operand, :%) to_number(input) % to_number(operand)
end end
private private
def to_number(obj) def to_number(obj)
case obj case obj
when Float when Numeric
BigDecimal.new(obj.to_s) obj
when Numeric when String
obj (obj.strip =~ /^\d+\.\d+$/) ? obj.to_f : obj.to_i
when String else
(obj.strip =~ /^\d+\.\d+$/) ? BigDecimal.new(obj) : obj.to_i 0
else end
0
end end
end
def apply_operation(input, operand, operation)
result = to_number(input).send(operation, to_number(operand))
result.is_a?(BigDecimal) ? result.to_f : result
end
end end
Template.register_filter(StandardFilters) Template.register_filter(StandardFilters)

View File

@@ -8,7 +8,7 @@ module Liquid
# The Strainer only allows method calls defined in filters given to it via Strainer.global_filter, # The Strainer only allows method calls defined in filters given to it via Strainer.global_filter,
# Context#add_filters or Template.register_filter # Context#add_filters or Template.register_filter
class Strainer #:nodoc: class Strainer #:nodoc:
@@filters = [] @@filters = {}
@@known_filters = Set.new @@known_filters = Set.new
@@known_methods = Set.new @@known_methods = Set.new
@@ -19,7 +19,7 @@ module Liquid
def self.global_filter(filter) def self.global_filter(filter)
raise ArgumentError, "Passed filter is not a module" unless filter.is_a?(Module) raise ArgumentError, "Passed filter is not a module" unless filter.is_a?(Module)
add_known_filter(filter) add_known_filter(filter)
@@filters << filter unless @@filters.include?(filter) @@filters[filter.name] = filter
end end
def self.add_known_filter(filter) def self.add_known_filter(filter)
@@ -34,7 +34,7 @@ module Liquid
def self.create(context) def self.create(context)
strainer = Strainer.new(context) strainer = Strainer.new(context)
@@filters.each { |m| strainer.extend(m) } @@filters.each { |k,m| strainer.extend(m) }
strainer strainer
end end

View File

@@ -23,4 +23,4 @@ module Liquid
end # Tag end # Tag
end # Liquid end # Tag

View File

@@ -23,10 +23,8 @@ module Liquid
end end
def render(context) def render(context)
val = @from.render(context) context.scopes.last[@to] = @from.render(context)
context.scopes.last[@to] = val ''
context.resource_limits[:assign_score_current] += (val.respond_to?(:length) ? val.length : 1)
''
end end
end end

View File

@@ -27,7 +27,6 @@ module Liquid
def render(context) def render(context)
output = super output = super
context.scopes.last[@to] = output context.scopes.last[@to] = output
context.resource_limits[:assign_score_current] += (output.respond_to?(:length) ? output.length : 1)
'' ''
end end
end end

View File

@@ -31,7 +31,7 @@ module Liquid
context.stack do context.stack do
execute_else_block = true execute_else_block = true
output = '' output = []
@blocks.each do |block| @blocks.each do |block|
if block.else? if block.else?
return render_all(block.attachment, context) if execute_else_block return render_all(block.attachment, context) if execute_else_block
@@ -48,16 +48,16 @@ module Liquid
def record_when_condition(markup) def record_when_condition(markup)
while markup while markup
# Create a new nodelist and assign it to the new block # Create a new nodelist and assign it to the new block
if not markup =~ WhenSyntax if not markup =~ WhenSyntax
raise SyntaxError.new("Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} ") raise SyntaxError.new("Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} ")
end end
markup = $2 markup = $2
block = Condition.new(@left, '==', $1) block = Condition.new(@left, '==', $1)
block.attach(@nodelist) block.attach(@nodelist)
@blocks.push(block) @blocks.push(block)
end end
end end

View File

@@ -19,11 +19,11 @@ module Liquid
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
case markup case markup
when NamedSyntax when NamedSyntax
@variables = variables_from_string($2) @variables = variables_from_string($2)
@name = $1 @name = $1
when SimpleSyntax when SimpleSyntax
@variables = variables_from_string(markup) @variables = variables_from_string(markup)
@name = "'#{@variables.to_s}'" @name = "'#{@variables.to_s}'"
else else
raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]") raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]")
end end
@@ -48,9 +48,9 @@ module Liquid
def variables_from_string(markup) def variables_from_string(markup)
markup.split(',').collect do |var| markup.split(',').collect do |var|
var =~ /\s*(#{QuotedFragment})\s*/o var =~ /\s*(#{QuotedFragment})\s*/o
$1 ? $1 : nil $1 ? $1 : nil
end.compact end.compact
end end
end end

View File

@@ -44,13 +44,14 @@ module Liquid
# forloop.last:: Returns true if the item is the last item. # forloop.last:: Returns true if the item is the last item.
# #
class For < Block class For < Block
Syntax = /\A(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o Syntax = /(\w+)\s+in\s+(#{QuotedFragment}+)\s*(reversed)?/o
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
if markup =~ Syntax if markup =~ Syntax
@variable_name = $1 @variable_name = $1
@collection_name = $2 @collection_name = $2
@name = "#{$1}-#{$2}" @name = "#{$1}-#{$2}"
@idx = "#{@name}-i"
@reversed = $3 @reversed = $3
@attributes = {} @attributes = {}
markup.scan(TagAttributes) do |key, value| markup.scan(TagAttributes) do |key, value|
@@ -87,14 +88,13 @@ module Liquid
limit = context[@attributes['limit']] limit = context[@attributes['limit']]
to = limit ? limit.to_i + from : nil to = limit ? limit.to_i + from : nil
segment = Utils.slice_collection_using_each(collection, from, to) segment = Utils.slice_collection_using_each(collection, from, to)
return render_else(context) if segment.empty? return render_else(context) if segment.empty?
segment.reverse! if @reversed segment.reverse! if @reversed
result = '' result = []
length = segment.length length = segment.length
@@ -102,17 +102,10 @@ module Liquid
context.registers[:for][@name] = from + segment.length context.registers[:for][@name] = from + segment.length
context.stack do context.stack do
context['forloop'] = lambda { Forloop.new(@name, @idx, length) }
segment.each_with_index do |item, index| segment.each_with_index do |item, index|
context.registers[:for][@idx] = index
context[@variable_name] = item context[@variable_name] = item
context['forloop'] = {
'name' => @name,
'length' => length,
'index' => index + 1,
'index0' => index,
'rindex' => length - index,
'rindex0' => length - index - 1,
'first' => (index == 0),
'last' => (index == length - 1) }
result << render_all(@for_block, context) result << render_all(@for_block, context)
@@ -129,6 +122,39 @@ module Liquid
private private
class Forloop < Liquid::Drop
attr_accessor :name, :length
def initialize(name, idx, length)
@name, @idx, @length = name, idx, length
end
def index
@context.registers[:for][@idx] + 1
end
def index0
@context.registers[:for][@idx]
end
def rindex
length - @context.registers[:for][@idx]
end
def rindex0
length - @context.registers[:for][@idx] - 1
end
def first
(@context.registers[:for][@idx] == 0)
end
def last
(@context.registers[:for][@idx] == length - 1)
end
end
def render_else(context) def render_else(context)
return @else_block ? [render_all(@else_block, context)] : '' return @else_block ? [render_all(@else_block, context)] : ''
end end

View File

@@ -15,7 +15,6 @@ module Liquid
SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]" SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/o
ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o ExpressionsAndOperators = /(?:\b(?:\s?and\s?|\s?or\s?)\b|(?:\s*(?!\b(?:\s?and\s?|\s?or\s?)\b)(?:#{QuotedFragment}|\S+)\s*)+)/o
BOOLEAN_OPERATORS = %w(and or)
def initialize(tag_name, markup, tokens) def initialize(tag_name, markup, tokens)
@blocks = [] @blocks = []
@@ -62,8 +61,7 @@ module Liquid
raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax raise(SyntaxError, SyntaxHelp) unless expressions.shift.to_s =~ Syntax
new_condition = Condition.new($1, $2, $3) new_condition = Condition.new($1, $2, $3)
raise SyntaxError, "invalid boolean operator" unless BOOLEAN_OPERATORS.include?(operator) new_condition.send(operator.to_sym, condition)
new_condition.send(operator, condition)
condition = new_condition condition = new_condition
end end
@@ -73,6 +71,8 @@ module Liquid
@blocks.push(block) @blocks.push(block)
@nodelist = block.attach(Array.new) @nodelist = block.attach(Array.new)
end end
end end
Template.register_tag('if', If) Template.register_tag('if', If)

View File

@@ -1,19 +1,4 @@
module Liquid module Liquid
# Include allows templates to relate with other templates
#
# Simply include another template:
#
# {% include 'product' %}
#
# Include a template with a local variable:
#
# {% include 'product' with products[0] %}
#
# Include a template for a collection:
#
# {% include 'product' for products %}
#
class Include < Tag class Include < Tag
Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/o
@@ -39,7 +24,8 @@ module Liquid
end end
def render(context) def render(context)
partial = load_cached_partial(context) source = _read_template_from_file_system(context)
partial = Liquid::Template.parse(source)
variable = context[@variable_name || @template_name[1..-2]] variable = context[@variable_name || @template_name[1..-2]]
context.stack do context.stack do
@@ -48,8 +34,8 @@ module Liquid
end end
if variable.is_a?(Array) if variable.is_a?(Array)
variable.collect do |var| variable.collect do |variable|
context[@template_name[1..-2]] = var context[@template_name[1..-2]] = variable
partial.render(context) partial.render(context)
end end
else else
@@ -60,21 +46,7 @@ module Liquid
end end
private private
def load_cached_partial(context) def _read_template_from_file_system(context)
cached_partials = context.registers[:cached_partials] || {}
template_name = context[@template_name]
if cached = cached_partials[template_name]
return cached
end
source = read_template_from_file_system(context)
partial = Liquid::Template.parse(source)
cached_partials[template_name] = partial
context.registers[:cached_partials] = cached_partials
partial
end
def read_template_from_file_system(context)
file_system = context.registers[:file_system] || Liquid::Template.file_system file_system = context.registers[:file_system] || Liquid::Template.file_system
# make read_template_file call backwards-compatible. # make read_template_file call backwards-compatible.

View File

@@ -1,14 +1,12 @@
module Liquid module Liquid
class Raw < Block class Raw < Block
FullTokenPossiblyInvalid = /^(.*)#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}$/o
def parse(tokens) def parse(tokens)
@nodelist ||= [] @nodelist ||= []
@nodelist.clear @nodelist.clear
while token = tokens.shift while token = tokens.shift
if token =~ FullTokenPossiblyInvalid if token =~ FullToken
@nodelist << $1 if $1 != "" if block_delimiter == $1
if block_delimiter == $2
end_tag end_tag
return return
end end
@@ -20,3 +18,4 @@ module Liquid
Template.register_tag('raw', Raw) Template.register_tag('raw', Raw)
end end

View File

@@ -11,9 +11,9 @@ module Liquid
context.stack do context.stack do
# First condition is interpreted backwards ( if not ) # First condition is interpreted backwards ( if not )
first_block = @blocks.first block = @blocks.first
unless first_block.evaluate(context) unless block.evaluate(context)
return render_all(first_block.attachment, context) return render_all(block.attachment, context)
end end
# After the first condition unless works just like if # After the first condition unless works just like if

View File

@@ -14,7 +14,7 @@ module Liquid
# template.render('user_name' => 'bob') # template.render('user_name' => 'bob')
# #
class Template class Template
attr_accessor :root, :resource_limits attr_accessor :root
@@file_system = BlankFileSystem.new @@file_system = BlankFileSystem.new
class << self class << self
@@ -50,7 +50,6 @@ module Liquid
# creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead # creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead
def initialize def initialize
@resource_limits = {}
end end
# Parse source code. # Parse source code.
@@ -93,13 +92,10 @@ module Liquid
context = case args.first context = case args.first
when Liquid::Context when Liquid::Context
args.shift args.shift
when Liquid::Drop
drop = args.shift
drop.context = Context.new([drop, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits)
when Hash when Hash
Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors, @resource_limits) Context.new([args.shift, assigns], instance_assigns, registers, @rethrow_errors)
when nil when nil
Context.new(assigns, instance_assigns, registers, @rethrow_errors, @resource_limits) Context.new(assigns, instance_assigns, registers, @rethrow_errors)
else else
raise ArgumentError, "Expect Hash or Liquid::Context as parameter" raise ArgumentError, "Expect Hash or Liquid::Context as parameter"
end end
@@ -124,11 +120,8 @@ module Liquid
begin begin
# render the nodelist. # render the nodelist.
# for performance reasons we get an array back here. join will make a string out of it. # for performance reasons we get a array back here. join will make a string out of it
result = @root.render(context) @root.render(context).join
result.respond_to?(:join) ? result.join : result
rescue Liquid::MemoryError => e
context.handle_error(e)
ensure ensure
@errors = context.errors @errors = context.errors
end end

View File

@@ -3,6 +3,7 @@ module Liquid
def self.slice_collection_using_each(collection, from, to) def self.slice_collection_using_each(collection, from, to)
segments = [] segments = []
index = 0 index = 0
yielded = 0
# Maintains Ruby 1.8.7 String#each behaviour on 1.9 # Maintains Ruby 1.8.7 String#each behaviour on 1.9
return [collection] if non_blank_string?(collection) return [collection] if non_blank_string?(collection)

View File

@@ -23,9 +23,9 @@ module Liquid
if match[2].match(/#{FilterSeparator}\s*(.*)/o) if match[2].match(/#{FilterSeparator}\s*(.*)/o)
filters = Regexp.last_match(1).scan(FilterParser) filters = Regexp.last_match(1).scan(FilterParser)
filters.each do |f| filters.each do |f|
if matches = f.match(/\s*(\w+)/) if matches = f.match(/\s*(\w+)(?:\s*#{FilterArgumentSeparator}(.*))?/)
filtername = matches[1] filtername = matches[1]
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten filterargs = matches[2].to_s.scan(/(?:\A|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
@filters << [filtername, filterargs] @filters << [filtername, filterargs]
end end
end end

View File

@@ -1,4 +0,0 @@
# encoding: utf-8
module Liquid
VERSION = "2.6.2"
end

View File

@@ -1,12 +1,8 @@
# encoding: utf-8 # encoding: utf-8
lib = File.expand_path('../lib/', __FILE__)
$:.unshift lib unless $:.include?(lib)
require "liquid/version"
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "liquid" s.name = "liquid"
s.version = Liquid::VERSION s.version = "2.5.0"
s.platform = Gem::Platform::RUBY s.platform = Gem::Platform::RUBY
s.summary = "A secure, non-evaling end user template engine with aesthetic markup." s.summary = "A secure, non-evaling end user template engine with aesthetic markup."
s.authors = ["Tobias Luetke"] s.authors = ["Tobias Luetke"]
@@ -17,9 +13,12 @@ Gem::Specification.new do |s|
s.required_rubygems_version = ">= 1.3.7" s.required_rubygems_version = ">= 1.3.7"
s.test_files = Dir.glob("{test}/**/*") s.test_files = Dir.glob("{test}/**/*")
s.files = Dir.glob("{lib}/**/*") + %w(MIT-LICENSE README.md) s.files = Dir.glob("{lib}/**/*") +
Dir.glob("{ext}/**/*") + %w(MIT-LICENSE README.md)
s.extensions = ['ext/liquid/extconf.rb']
s.extra_rdoc_files = ["History.md", "README.md"] s.extra_rdoc_files = ["History.md", "README.md"]
s.require_path = "lib" s.require_paths = ["lib", "ext"]
end end

View File

@@ -4,8 +4,8 @@ require File.dirname(__FILE__) + '/theme_runner'
profiler = ThemeRunner.new profiler = ThemeRunner.new
Benchmark.bmbm do |x| Benchmark.bm do |x|
x.report("parse:") { 100.times { profiler.compile } } # x.report("parse:") { 100.times { profiler.compile } }
x.report("parse & run:") { 100.times { profiler.run } } x.report("parse & run:") { 100.times { profiler.run } }
end end

View File

@@ -6,14 +6,12 @@ profiler = ThemeRunner.new
puts 'Running profiler...' puts 'Running profiler...'
results = profiler.run results = profiler.run_profile
puts 'Success' puts 'Success'
puts
[RubyProf::FlatPrinter, RubyProf::GraphPrinter, RubyProf::GraphHtmlPrinter, RubyProf::CallTreePrinter].each do |klass| filename = (ENV['TMP'] || '/tmp') + "/callgrind.liquid.txt"
filename = (ENV['TMP'] || '/tmp') + (klass.name.include?('Html') ? "/liquid.#{klass.name.downcase}.html" : "/callgrind.liquid.#{klass.name.downcase}.txt") File.open(filename, "w+") do |fp|
filename.gsub!(/:+/, '_') RubyProf::CallTreePrinter.new(results).print(fp, :print_file => true)
File.open(filename, "w+") { |fp| klass.new(results).print(fp, :print_file => true) }
$stderr.puts "wrote #{klass.name} output to #{filename}"
end end
$stderr.puts "wrote RubyProf::CallTreePrinter output to #{filename}"

View File

@@ -17,14 +17,14 @@
<ul id="comment-list"> <ul id="comment-list">
{% for comment in article.comments %} {% for comment in article.comments %}
<li> <li>
<div class="comment-details"> <div class="comment-details">
<span class="comment-author">{{ comment.author }}</span> said on <span class="comment-date">{{ comment.created_at | date: "%B %d, %Y" }}</span>: <span class="comment-author">{{ comment.author }}</span> said on <span class="comment-date">{{ comment.created_at | date: "%B %d, %Y" }}</span>:
</div> </div>
<div class="comment"> <div class="comment">
{{ comment.content }} {{ comment.content }}
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@@ -10,7 +10,7 @@
<h3 class="title"> <h3 class="title">
<a href="{{article.url}}">{{ article.title }}</a> <a href="{{article.url}}">{{ article.title }}</a>
</h3> </h3>
<h4 class="date">Posted on {{ article.created_at | date: "%B %d, '%y" }} by {{ article.author }}.</h4> <h4 class="date">Posted on {{ article.created_at | date: "%B %d, '%y" }} by {{ article.author }}.</h4>
</div> </div>
<div class="article-body textile"> <div class="article-body textile">

View File

@@ -20,17 +20,17 @@
{% for item in cart.items %} {% for item in cart.items %}
<li id="item-{{item.id}}" class="clearfix"> <li id="item-{{item.id}}" class="clearfix">
<div class="thumb"> <div class="thumb">
<div class="prodimage"> <div class="prodimage">
<a href="{{item.product.url}}" title="View {{item.title}} Page"><img src="{{item.product.featured_image | product_img_url: 'thumb' }}" alt="{{item.title | escape }}" /></a> <a href="{{item.product.url}}" title="View {{item.title}} Page"><img src="{{item.product.featured_image | product_img_url: 'thumb' }}" alt="{{item.title | escape }}" /></a>
</div></div> </div></div>
<h3 style="padding-right: 150px"> <h3 style="padding-right: 150px">
<a href="{{item.product.url}}" title="View {{item.title | escape }} Page"> <a href="{{item.product.url}}" title="View {{item.title | escape }} Page">
{{ item.title }} {{ item.title }}
{% if item.variant.available == true %} {% if item.variant.available == true %}
({{item.variant.title}}) ({{item.variant.title}})
{% endif %} {% endif %}
</a> </a>
</h3> </h3>
<small class="itemcost">Costs {{ item.price | money }} each, <span class="money">{{item.line_price | money }}</span> total.</small> <small class="itemcost">Costs {{ item.price | money }} each, <span class="money">{{item.line_price | money }}</span> total.</small>
<p class="right"> <p class="right">
<label for="updates">How many? </label> <label for="updates">How many? </label>
@@ -49,10 +49,10 @@
</div> </div>
<div class="info"> <div class="info">
<input type="image" value="Checkout!" name="checkout" src="{{ 'checkout.gif' | asset_url }}" /> <input type="image" value="Checkout!" name="checkout" src="{{ 'checkout.gif' | asset_url }}" />
</div> </div>
{% if additional_checkout_buttons %} {% if additional_checkout_buttons %}
<div class="additional-checkout-buttons"> <div class="additional-checkout-buttons">
<p>- or -</p> <p>- or -</p>
{{ content_for_additional_checkout_buttons }} {{ content_for_additional_checkout_buttons }}

View File

@@ -9,7 +9,7 @@
<div class="description"> <div class="description">
<h3><a href="{{product.url}}">{{product.title}}</a></h3> <h3><a href="{{product.url}}">{{product.title}}</a></h3>
<p>{{ product.description | strip_html | truncatewords: 35 }}</p> <p>{{ product.description | strip_html | truncatewords: 35 }}</p>
<p class="money">{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}</p> <p class="money">{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}</p>
</div> </div>
</li> </li>
{% endfor %} {% endfor %}

View File

@@ -5,7 +5,7 @@
<a href="{{ product.url }}"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ product.url }}"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a>
<h3><a href="{{ product.url }}">{{ product.title }}</a></h3> <h3><a href="{{ product.url }}">{{ product.title }}</a></h3>
<div class="description">{{ product.description | strip_html | truncatewords: 18 }}</div> <div class="description">{{ product.description | strip_html | truncatewords: 18 }}</div>
<p class="money">{{ product.price_min | money }}</p> <p class="money">{{ product.price_min | money }}</p>
</div> </div>
{% endfor %} {% endfor %}
{% for product in collections.frontpage.products offset:1 %} {% for product in collections.frontpage.products offset:1 %}
@@ -18,30 +18,30 @@
</div></div></div> </div></div></div>
<div id="mainarticle"> <div id="mainarticle">
{% assign article = pages.frontpage %} {% assign article = pages.frontpage %}
{% if article.content != "" %} {% if article.content != "" %}
<h2>{{ article.title }}</h2> <h2>{{ article.title }}</h2>
<div class="article-body textile"> <div class="article-body textile">
{{ article.content }} {{ article.content }}
</div> </div>
{% else %} {% else %}
<div class="article-body textile"> <div class="article-body textile">
In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br /> In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br />
{{ "Learn more about handles" | link_to "http://wiki.shopify.com/Handle" }} {{ "Learn more about handles" | link_to "http://wiki.shopify.com/Handle" }}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<br style="clear: both;" /> <br style="clear: both;" />
<div id="articles"> <div id="articles">
{% for article in blogs.news.articles offset:1 %} {% for article in blogs.news.articles offset:1 %}
<div class="article"> <div class="article">
<h2>{{ article.title }}</h2> <h2>{{ article.title }}</h2>
<div class="article-body textile"> <div class="article-body textile">
{{ article.content }} {{ article.content }}
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -1,18 +1,18 @@
<div id="productpage"> <div id="productpage">
<div id="productimages"><div id="productimages-top"><div id="productimages-bottom"> <div id="productimages"><div id="productimages-top"><div id="productimages-bottom">
{% for image in product.images %} {% for image in product.images %}
{% if forloop.first %} {% if forloop.first %}
<a href="{{ image | product_img_url: 'large' }}" class="productimage" rel="lightbox"> <a href="{{ image | product_img_url: 'large' }}" class="productimage" rel="lightbox">
<img src="{{ image | product_img_url: 'medium'}}" alt="{{product.title | escape }}" /> <img src="{{ image | product_img_url: 'medium'}}" alt="{{product.title | escape }}" />
</a> </a>
{% else %} {% else %}
<a href="{{ image | product_img_url: 'large' }}" class="productimage-small" rel="lightbox"> <a href="{{ image | product_img_url: 'large' }}" class="productimage-small" rel="lightbox">
<img src="{{ image | product_img_url: 'small'}}" alt="{{product.title | escape }}" /> <img src="{{ image | product_img_url: 'small'}}" alt="{{product.title | escape }}" />
</a> </a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div></div></div> </div></div></div>
<h2>{{ product.title }}</h2> <h2>{{ product.title }}</h2>
@@ -26,15 +26,15 @@
<div id="variant-add"> <div id="variant-add">
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<select id="variant-select" name="id" class="product-info-options"> <select id="variant-select" name="id" class="product-info-options">
{% for variant in product.variants %} {% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option> <option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option>
{% endfor %} {% endfor %}
</select> </select>
<div id="price-field" class="price"></div> <div id="price-field" class="price"></div>
<div style="text-align:center;"><input type="image" name="add" value="Add to Cart" id="add" src="{{ 'addtocart.gif' | asset_url }}" /></div> <div style="text-align:center;"><input type="image" name="add" value="Add to Cart" id="add" src="{{ 'addtocart.gif' | asset_url }}" /></div>
</form> </form>
</div> </div>

View File

@@ -1,67 +1,67 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>{{shop.name}} - {{page_title}}</title> <title>{{shop.name}} - {{page_title}}</title>
{{ 'textile.css' | global_asset_url | stylesheet_tag }} {{ 'textile.css' | global_asset_url | stylesheet_tag }}
{{ 'lightbox/v204/lightbox.css' | global_asset_url | stylesheet_tag }} {{ 'lightbox/v204/lightbox.css' | global_asset_url | stylesheet_tag }}
{{ 'prototype/1.6/prototype.js' | global_asset_url | script_tag }} {{ 'prototype/1.6/prototype.js' | global_asset_url | script_tag }}
{{ 'scriptaculous/1.8.2/scriptaculous.js' | global_asset_url | script_tag }} {{ 'scriptaculous/1.8.2/scriptaculous.js' | global_asset_url | script_tag }}
{{ 'lightbox/v204/lightbox.js' | global_asset_url | script_tag }} {{ 'lightbox/v204/lightbox.js' | global_asset_url | script_tag }}
{{ 'option_selection.js' | shopify_asset_url | script_tag }} {{ 'option_selection.js' | shopify_asset_url | script_tag }}
{{ 'layout.css' | asset_url | stylesheet_tag }} {{ 'layout.css' | asset_url | stylesheet_tag }}
{{ 'shop.js' | asset_url | script_tag }} {{ 'shop.js' | asset_url | script_tag }}
{{ content_for_header }} {{ content_for_header }}
</head> </head>
<body id="page-{{template}}"> <body id="page-{{template}}">
<p class="hide"><a href="#rightsiders">Skip to navigation.</a></p> <p class="hide"><a href="#rightsiders">Skip to navigation.</a></p>
<!-- mini cart --> <!-- mini cart -->
{% if cart.item_count > 0 %} {% if cart.item_count > 0 %}
<div id="minicart" style="display:none;"><div id="minicart-inner"> <div id="minicart" style="display:none;"><div id="minicart-inner">
<div id="minicart-items"> <div id="minicart-items">
<h2>There {{ cart.item_count | pluralize: 'is', 'are' }} {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} in <a href="/cart" title="View your cart">your cart</a>!</h2><h4 style="font-size: 16px; margin: 0 0 10px 0; padding: 0;">Your subtotal is {{ cart.total_price | money }}.</h4> <h2>There {{ cart.item_count | pluralize: 'is', 'are' }} {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} in <a href="/cart" title="View your cart">your cart</a>!</h2><h4 style="font-size: 16px; margin: 0 0 10px 0; padding: 0;">Your subtotal is {{ cart.total_price | money }}.</h4>
{% for item in cart.items %} {% for item in cart.items %}
<div class="thumb"> <div class="thumb">
<div class="prodimage"><a href="{{item.product.url}}" onMouseover="tooltip('{{ item.quantity }} x {{ item.title }} ({{ item.variant.title }})', 200)"; onMouseout="hidetooltip()"><img src="{{ item.product.featured_image | product_img_url: 'thumb' }}" /></a></div> <div class="prodimage"><a href="{{item.product.url}}" onMouseover="tooltip('{{ item.quantity }} x {{ item.title }} ({{ item.variant.title }})', 200)"; onMouseout="hidetooltip()"><img src="{{ item.product.featured_image | product_img_url: 'thumb' }}" /></a></div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<br style="clear:both;" /> <br style="clear:both;" />
</div></div> </div></div>
{% endif %} {% endif %}
<div id="container"> <div id="container">
<div id="header"> <div id="header">
<!-- Begin Header --> <!-- Begin Header -->
<h1 id="logo"><a href="/" title="Go Home">{{shop.name}}</a></h1> <h1 id="logo"><a href="/" title="Go Home">{{shop.name}}</a></h1>
<div id="cartlinks"> <div id="cartlinks">
{% if cart.item_count > 0 %} {% if cart.item_count > 0 %}
<h2 id="cartcount"><a href="/cart" onMouseover="tooltip('There {{ cart.item_count | pluralize: 'is', 'are' }} {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} in your cart!', 200)"; onMouseout="hidetooltip()">{{ cart.item_count }} {{ cart.item_count | pluralize: 'thing', 'things' }}!</a></h2> <h2 id="cartcount"><a href="/cart" onMouseover="tooltip('There {{ cart.item_count | pluralize: 'is', 'are' }} {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} in your cart!', 200)"; onMouseout="hidetooltip()">{{ cart.item_count }} {{ cart.item_count | pluralize: 'thing', 'things' }}!</a></h2>
<a href="/cart" id="minicartswitch" onclick="superSwitch(this, 'minicart', 'Close Mini Cart'); return false;" id="cartswitch">View Mini Cart ({{ cart.total_price | money }})</a> <a href="/cart" id="minicartswitch" onclick="superSwitch(this, 'minicart', 'Close Mini Cart'); return false;" id="cartswitch">View Mini Cart ({{ cart.total_price | money }})</a>
{% endif %} {% endif %}
</div> </div>
<!-- End Header --> <!-- End Header -->
</div> </div>
<hr /> <hr />
<div id="main"> <div id="main">
<div id="content"> <div id="content">
<div id="innercontent"> <div id="innercontent">
{{ content_for_layout }} {{ content_for_layout }}
</div> </div>
</div> </div>
<hr /> <hr />
<div id="rightsiders"> <div id="rightsiders">
<ul class="rightlinks"> <ul class="rightlinks">
{% for link in linklists.main-menu.links %} {% for link in linklists.main-menu.links %}
@@ -83,18 +83,18 @@
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<hr /><br style="clear:both;" /> <hr /><br style="clear:both;" />
<div id="footer"> <div id="footer">
<div class="footerinner"> <div class="footerinner">
All prices are in {{ shop.currency }}. All prices are in {{ shop.currency }}.
Powered by <a href="http://www.shopify.com" title="Shopify, Hosted E-Commerce">Shopify</a>. Powered by <a href="http://www.shopify.com" title="Shopify, Hosted E-Commerce">Shopify</a>.
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="tooltip"></div> <div id="tooltip"></div>

View File

@@ -21,10 +21,10 @@
{{ comment.content }} {{ comment.content }}
</div> </div>
<div class="comment-details"> <div class="comment-details">
Posted by {{ comment.author }} on {{ comment.created_at | date: "%B %d, %Y" }} Posted by {{ comment.author }} on {{ comment.created_at | date: "%B %d, %Y" }}
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@@ -9,7 +9,7 @@
{% if cart.item_count == 0 %} {% if cart.item_count == 0 %}
<p>Your shopping cart is empty...</p> <p>Your shopping cart is empty...</p>
<p><a href="/"><img src="{{ 'continue_shopping_icon.gif' | asset_url }}" alt="Continue shopping"/></a><p> <p><a href="/"><img src="{{ 'continue_shopping_icon.gif' | asset_url }}" alt="Continue shopping"/></a><p>
{% else %} {% else %}
<form action="/cart" method="post" id="cart"> <form action="/cart" method="post" id="cart">
@@ -26,21 +26,21 @@
{% for item in cart.items %} {% for item in cart.items %}
<tr class="{% cycle 'odd', 'even' %}"> <tr class="{% cycle 'odd', 'even' %}">
<td class="short">{{ item.product.featured_image | product_img_url: 'thumb' | img_tag }}</td> <td class="short">{{ item.product.featured_image | product_img_url: 'thumb' | img_tag }}</td>
<td><a href="{{item.product.url}}">{{ item.title }}</a></td> <td><a href="{{item.product.url}}">{{ item.title }}</a></td>
<td class="short"><input type="text" class="quantity" name="updates[{{item.variant.id}}]" id="updates_{{item.variant.id}}" value="{{item.quantity}}" onfocus="this.select();"/></td> <td class="short"><input type="text" class="quantity" name="updates[{{item.variant.id}}]" id="updates_{{item.variant.id}}" value="{{item.quantity}}" onfocus="this.select();"/></td>
<td class="cart-price">{{ item.price | money }}</td> <td class="cart-price">{{ item.price | money }}</td>
<td class="cart-price">{{item.line_price | money }}</td> <td class="cart-price">{{item.line_price | money }}</td>
<td class="short"><a href="#" onclick="remove_item({{item.variant.id}}); return false;" class="remove"><img src="{{ 'cancel_icon.gif' | asset_url }}" alt="Remove" /></a></td> <td class="short"><a href="#" onclick="remove_item({{item.variant.id}}); return false;" class="remove"><img src="{{ 'cancel_icon.gif' | asset_url }}" alt="Remove" /></a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
<p class="updatebtn"><input type="image" value="Update Cart" name="update" src="{{ 'update_icon.gif' | asset_url }}" alt="Update" /></p> <p class="updatebtn"><input type="image" value="Update Cart" name="update" src="{{ 'update_icon.gif' | asset_url }}" alt="Update" /></p>
<p class="subtotal"> <p class="subtotal">
<strong>Subtotal:</strong> {{cart.total_price | money_with_currency }} <strong>Subtotal:</strong> {{cart.total_price | money_with_currency }}
</p> </p>
<p class="checkout"><input type="image" src="{{ 'checkout_icon.gif' | asset_url }}" alt="Proceed to Checkout" value="Proceed to Checkout" name="checkout" /></p> <p class="checkout"><input type="image" src="{{ 'checkout_icon.gif' | asset_url }}" alt="Proceed to Checkout" value="Proceed to Checkout" name="checkout" /></p>
{% if additional_checkout_buttons %} {% if additional_checkout_buttons %}
<div class="additional-checkout-buttons"> <div class="additional-checkout-buttons">
<p>- or -</p> <p>- or -</p>
{{ content_for_additional_checkout_buttons }} {{ content_for_additional_checkout_buttons }}

View File

@@ -15,7 +15,7 @@
<div class="prod-list-description"> <div class="prod-list-description">
<h3><a href="{{product.url}}">{{product.title}}</a></h3> <h3><a href="{{product.url}}">{{product.title}}</a></h3>
<p>{{ product.description | strip_html | truncatewords: 35 }}</p> <p>{{ product.description | strip_html | truncatewords: 35 }}</p>
<p class="prd-price">{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}</p> <p class="prd-price">{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}</p>
</div> </div>
</li> </li>
{% endfor %} {% endfor %}

View File

@@ -1,32 +1,32 @@
<div id="home-page"> <div id="home-page">
<h3 class="heading-shaded">Featured products...</h3> <h3 class="heading-shaded">Featured products...</h3>
<div class="featured-prod-row clearfix"> <div class="featured-prod-row clearfix">
{% for product in collections.frontpage.products %} {% for product in collections.frontpage.products %}
<div class="featured-prod-item"> <div class="featured-prod-item">
<p> <p>
<a href="{{product.url}}"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a> <a href="{{product.url}}"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a>
</p> </p>
<h4><a href="{{product.url}}">{{product.title}}</a></h4> <h4><a href="{{product.url}}">{{product.title}}</a></h4>
{% if product.compare_at_price %} {% if product.compare_at_price %}
{% if product.price_min != product.compare_at_price %} {% if product.price_min != product.compare_at_price %}
<p class="prd-price">Was:<del>{{product.compare_at_price | money}}</del></p> <p class="prd-price">Was:<del>{{product.compare_at_price | money}}</del></p>
<p class="prd-price"><ins>Now: {{product.price_min | money}}</ins></p> <p class="prd-price"><ins>Now: {{product.price_min | money}}</ins></p>
{% endif %} {% endif %}
{% else %} {% else %}
<p class="prd-price"><ins>{{product.price_min | money}}</ins></p> <p class="prd-price"><ins>{{product.price_min | money}}</ins></p>
{% endif %} {% endif %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<div id="articles"> <div id="articles">
{% assign article = pages.frontpage %} {% assign article = pages.frontpage %}
{% if article.content != "" %} {% if article.content != "" %}
<h3>{{ article.title }}</h3> <h3>{{ article.title }}</h3>
{{ article.content }} {{ article.content }}
{% else %} {% else %}
In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br /> In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br />
{{ "Learn more about handles" | link_to "http://wiki.shopify.com/Handle" }} {{ "Learn more about handles" | link_to "http://wiki.shopify.com/Handle" }}
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@@ -1,31 +1,31 @@
<div id="product-page"> <div id="product-page">
<h2 class="heading-shaded">{{ product.title }}</h2> <h2 class="heading-shaded">{{ product.title }}</h2>
<div id="product-details"> <div id="product-details">
<div id="product-images"> <div id="product-images">
{% for image in product.images %} {% for image in product.images %}
{% if forloop.first %} {% if forloop.first %}
<a href="{{ image | product_img_url: 'large' }}" class="product-image" rel="lightbox[ product]" title=""> <a href="{{ image | product_img_url: 'large' }}" class="product-image" rel="lightbox[ product]" title="">
<img src="{{ image | product_img_url: 'medium'}}" alt="{{product.title | escape }}" /> <img src="{{ image | product_img_url: 'medium'}}" alt="{{product.title | escape }}" />
</a> </a>
{% else %} {% else %}
<a href="{{ image | product_img_url: 'large' }}" class="product-image-small" rel="lightbox[ product]" title=""> <a href="{{ image | product_img_url: 'large' }}" class="product-image-small" rel="lightbox[ product]" title="">
<img src="{{ image | product_img_url: 'small'}}" alt="{{product.title | escape }}" /> <img src="{{ image | product_img_url: 'small'}}" alt="{{product.title | escape }}" />
</a> </a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
<ul id="product-info"> <ul id="product-info">
<li>Vendor: {{ product.vendor | link_to_vendor }}</li> <li>Vendor: {{ product.vendor | link_to_vendor }}</li>
<li>Type: {{ product.type | link_to_type }}</li> <li>Type: {{ product.type | link_to_type }}</li>
</ul> </ul>
<small>{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}</small> <small>{{ product.price_min | money }}{% if product.price_varies %} - {{ product.price_max | money }}{% endif %}</small>
<div id="product-options"> <div id="product-options">
{% if product.available %} {% if product.available %}
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<select id="product-select" name='id'> <select id="product-select" name='id'>
{% for variant in product.variants %} {% for variant in product.variants %}
@@ -35,16 +35,16 @@
<div id="price-field"></div> <div id="price-field"></div>
<div class="add-to-cart"><input type="image" name="add" value="Add to Cart" id="add" src="{{ 'add-to-cart.gif' | asset_url }}" /></div> <div class="add-to-cart"><input type="image" name="add" value="Add to Cart" id="add" src="{{ 'add-to-cart.gif' | asset_url }}" /></div>
</form> </form>
{% else %} {% else %}
<span>Sold Out!</span> <span>Sold Out!</span>
{% endif %} {% endif %}
</div> </div>
<div class="product-description"> <div class="product-description">
{{ product.description }} {{ product.description }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,15 +2,15 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head> <head>
<title>{{shop.name}} - {{page_title}}</title> <title>{{shop.name}} - {{page_title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
{{ 'main.css' | asset_url | stylesheet_tag }} {{ 'main.css' | asset_url | stylesheet_tag }}
{{ 'shop.js' | asset_url | script_tag }} {{ 'shop.js' | asset_url | script_tag }}
{{ 'mootools.js' | asset_url | script_tag }} {{ 'mootools.js' | asset_url | script_tag }}
{{ 'slimbox.js' | asset_url | script_tag }} {{ 'slimbox.js' | asset_url | script_tag }}
{{ 'option_selection.js' | shopify_asset_url | script_tag }} {{ 'option_selection.js' | shopify_asset_url | script_tag }}
{{ 'slimbox.css' | asset_url | stylesheet_tag }} {{ 'slimbox.css' | asset_url | stylesheet_tag }}
{{ content_for_header }} {{ content_for_header }}
</head> </head>
@@ -18,67 +18,67 @@
<body id="page-{{template}}"> <body id="page-{{template}}">
<p class="hide"><a href="#navigation">Skip to navigation.</a></p> <p class="hide"><a href="#navigation">Skip to navigation.</a></p>
<div id="wrapper"> <div id="wrapper">
<div class="content clearfix"> <div class="content clearfix">
<div id="header"> <div id="header">
<h2><a href="/">{{shop.name}}</a></h2> <h2><a href="/">{{shop.name}}</a></h2>
</div> </div>
<div id="left-col"> <div id="left-col">
{{ content_for_layout }} {{ content_for_layout }}
</div> </div>
<div id="right-col"> <div id="right-col">
{% if template != 'cart' %} {% if template != 'cart' %}
<div id="cart-right-col"> <div id="cart-right-col">
<dl id="cart-right-col-info"> <dl id="cart-right-col-info">
<dt>Shopping Cart</dt> <dt>Shopping Cart</dt>
<dd> <dd>
{% if cart.item_count != 0 %} {% if cart.item_count != 0 %}
<a href="/cart">{{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}</a> in your cart <a href="/cart">{{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}</a> in your cart
{% else %} {% else %}
Your cart is empty Your cart is empty
{% endif %} {% endif %}
</dd> </dd>
</dl> </dl>
</div> </div>
{% endif %} {% endif %}
<div id="search"> <div id="search">
<dl id="searchbox"> <dl id="searchbox">
<dt>Search</dt> <dt>Search</dt>
<dd> <dd>
<form action="/search" method="get"> <form action="/search" method="get">
<fieldset> <fieldset>
<input class="search-input" type="text" onclick="this.select()" value="Search this shop..." name="q" /> <input class="search-input" type="text" onclick="this.select()" value="Search this shop..." name="q" />
</fieldset> </fieldset>
</form> </form>
</dd> </dd>
</dl> </dl>
</div> </div>
<div id="navigation"> <div id="navigation">
<dl class="navbar"> <dl class="navbar">
<dt>Navigation</dt> <dt>Navigation</dt>
{% for link in linklists.main-menu.links %} {% for link in linklists.main-menu.links %}
<dd>{{ link.title | link_to: link.url }}</dd> <dd>{{ link.title | link_to: link.url }}</dd>
{% endfor %} {% endfor %}
</dl> </dl>
{% if tags %} {% if tags %}
<dl class="navbar"> <dl class="navbar">
<dt>Tags</dt> <dt>Tags</dt>
{% for tag in collection.tags %} {% for tag in collection.tags %}
<dd>{{ tag | highlight_active_tag | link_to_tag: tag }}</dd> <dd>{{ tag | highlight_active_tag | link_to_tag: tag }}</dd>
{% endfor %} {% endfor %}
</dl> </dl>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div> </div>
<div id="content-padding"></div> <div id="content-padding"></div>
</div> </div>
<div id="footer"> <div id="footer">
{% for link in linklists.footer.links %} {% for link in linklists.footer.links %}
{{ link.title | link_to: link.url }} {% if forloop.rindex != 1 %} | {% endif %} {{ link.title | link_to: link.url }} {% if forloop.rindex != 1 %} | {% endif %}
{% endfor %} {% endfor %}
</div> </div>
</body> </body>

View File

@@ -1,56 +1,56 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<div id="text-page"> <div id="text-page">
<div class="entry"> <div class="entry">
<h1>Oh no!</h1> <h1>Oh no!</h1>
<div class="entry-post"> <div class="entry-post">
Seems like you are looking for something that just isn't here. <a href="/">Try heading back to our main page</a>. Or you can checkout some of our featured products below. Seems like you are looking for something that just isn't here. <a href="/">Try heading back to our main page</a>. Or you can checkout some of our featured products below.
</div> </div>
</div> </div>
</div> </div>
<h1>Featured Products</h1> <h1>Featured Products</h1>
<ul class="item-list clearfix"> <ul class="item-list clearfix">
{% for product in collections.frontpage.products %} {% for product in collections.frontpage.products %}
<li> <li>
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<div class="item-list-item"> <div class="item-list-item">
<div class="ili-top clearfix"> <div class="ili-top clearfix">
<div class="ili-top-content"> <div class="ili-top-content">
<h2><a href="{{product.url}}">{{product.title}}</a></h2> <h2><a href="{{product.url}}">{{product.title}}</a></h2>
<p>{{ product.description | truncatewords: 15 }}</p> <p>{{ product.description | truncatewords: 15 }}</p>
</div> </div>
<a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a> <a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a>
</div> </div>
<div class="ili-bottom clearfix"> <div class="ili-bottom clearfix">
<p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p> <p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p>
<input type="submit" class="" value="Add to Basket" /> <input type="submit" class="" value="Add to Basket" />
<p> <p>
<a href="{{product.url}}">View Details</a> <a href="{{product.url}}">View Details</a>
<span> <span>
{% if product.compare_at_price %} {% if product.compare_at_price %}
{% if product.price_min != product.compare_at_price %} {% if product.price_min != product.compare_at_price %}
{{product.compare_at_price | money}} - {{product.compare_at_price | money}} -
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong> <strong>
{{product.price_min | money}} {{product.price_min | money}}
</strong> </strong>
</span> </span>
</p> </p>
</div> </div>
</div> </div>
</form> </form>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<!-- end page --> <!-- end page -->

View File

@@ -1,15 +1,15 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<div id="text-page"> <div id="text-page">
<div class="entry"> <div class="entry">
<h1><span>{{article.title}}</span></h1> <h1><span>{{article.title}}</span></h1>
<div class="entry-post"> <div class="entry-post">
<div class="meta">{{ article.created_at | date: "%b %d" }}</div> <div class="meta">{{ article.created_at | date: "%b %d" }}</div>
{{ article.content }} {{ article.content }}
</div> </div>
<!-- Comments --> <!-- Comments -->
{% if blog.comments_enabled? %} {% if blog.comments_enabled? %}
<div id="comments"> <div id="comments">
<h2>Comments</h2> <h2>Comments</h2>
@@ -22,10 +22,10 @@
{{ comment.content }} {{ comment.content }}
</div> </div>
<div class="comment-details"> <div class="comment-details">
Posted by <span class="comment-author">{{ comment.author }}</span> on <span class="comment-date">{{ comment.created_at | date: "%B %d, %Y" }}</span> Posted by <span class="comment-author">{{ comment.author }}</span> on <span class="comment-date">{{ comment.created_at | date: "%B %d, %Y" }}</span>
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
@@ -75,24 +75,24 @@
<!-- END Comments --> <!-- END Comments -->
</div> </div>
</div> </div>
<div id="three-reasons" class="clearfix"> <div id="three-reasons" class="clearfix">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bit encrypted.</p> <p>Checkout is 256bit encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -1,41 +1,41 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<div id="text-page"> <div id="text-page">
<h1>Post from our blog...</h1> <h1>Post from our blog...</h1>
{% paginate blog.articles by 20 %} {% paginate blog.articles by 20 %}
{% for article in blog.articles %} {% for article in blog.articles %}
<div class="entry"> <div class="entry">
<h1><span><a href="{{ article.url }}">{{ article.title }}</a></span></h1> <h1><span><a href="{{ article.url }}">{{ article.title }}</a></span></h1>
<div class="entry-post"> <div class="entry-post">
<div class="meta">{{ article.created_at | date: "%b %d" }}</div> <div class="meta">{{ article.created_at | date: "%b %d" }}</div>
{{ article.content }} {{ article.content }}
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
<div class="paginate clearfix"> <div class="paginate clearfix">
{{ paginate | default_pagination }} {{ paginate | default_pagination }}
</div> </div>
{% endpaginate %} {% endpaginate %}
</div> </div>
<div id="three-reasons" class="clearfix"> <div id="three-reasons" class="clearfix">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bit encrypted.</p> <p>Checkout is 256bit encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -5,55 +5,55 @@
} }
</script> </script>
<div id="page" class="innerpage clearfix">. <div id="page" class="innerpage clearfix">.
{% if cart.item_count == 0 %} {% if cart.item_count == 0 %}
<h1>Your cart is currently empty.</h1> <h1>Your cart is currently empty.</h1>
{% else %} {% else %}
<h1>Your Cart <span>({{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}, {{cart.total_price | money_with_currency }} total)</span></h1> <h1>Your Cart <span>({{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}, {{cart.total_price | money_with_currency }} total)</span></h1>
<form action="/cart" method="post" id="cart-form"> <form action="/cart" method="post" id="cart-form">
<div id="cart-wrap"> <div id="cart-wrap">
<table width="100%" border="0" cellspacing="0" cellpadding="0"> <table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr> <tr>
<th scope="col" class="td-image"><label>Image</label></th> <th scope="col" class="td-image"><label>Image</label></th>
<th scope="col" class="td-title"><label>Product Title</label></th> <th scope="col" class="td-title"><label>Product Title</label></th>
<th scope="col" class="td-count"><label>Count</label></th> <th scope="col" class="td-count"><label>Count</label></th>
<th scope="col" class="td-price"><label>Cost</label></th> <th scope="col" class="td-price"><label>Cost</label></th>
<th scope="col" class="td-delete"><label>Remove</label></th> <th scope="col" class="td-delete"><label>Remove</label></th>
</tr> </tr>
{% for item in cart.items %} {% for item in cart.items %}
<tr class="{% cycle 'reg', 'alt' %}"> <tr class="{% cycle 'reg', 'alt' %}">
<td colspan="5"> <td colspan="5">
<table width="100%" border="0" cellspacing="0" cellpadding="0"> <table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr> <tr>
<td class="td-image"><a href="{{item.product.url}}">{{ item.product.featured_image | product_img_url: 'thumb' | img_tag }}</a></td> <td class="td-image"><a href="{{item.product.url}}">{{ item.product.featured_image | product_img_url: 'thumb' | img_tag }}</a></td>
<td class="td-title"><p>{{ item.title }}</p></td> <td class="td-title"><p>{{ item.title }}</p></td>
<td class="td-count"><label>Count:</label> <input type="text" class="quantity item-count" name="updates[{{item.variant.id}}]" id="updates_{{item.variant.id}}" value="{{item.quantity}}" onfocus="this.select();"/></td> <td class="td-count"><label>Count:</label> <input type="text" class="quantity item-count" name="updates[{{item.variant.id}}]" id="updates_{{item.variant.id}}" value="{{item.quantity}}" onfocus="this.select();"/></td>
<td class="td-price">{{item.line_price | money }}</td> <td class="td-price">{{item.line_price | money }}</td>
<td class="td-delete"><a href="#" onclick="remove_item({{item.variant.id}}); return false;">Remove</a></td> <td class="td-delete"><a href="#" onclick="remove_item({{item.variant.id}}); return false;">Remove</a></td>
</tr> </tr>
</table> </table>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
<div id="finish-up"> <div id="finish-up">
<div class="latest-news-box"> <div class="latest-news-box">
{{ pages.shopping-cart.content }} {{ pages.shopping-cart.content }}
</div> </div>
<p class="order-total"> <p class="order-total">
<span><strong>Order Total:</strong> {{cart.total_price | money_with_currency }}</span> <span><strong>Order Total:</strong> {{cart.total_price | money_with_currency }}</span>
</p> </p>
<p class="update-cart"><input type="submit" value="Refresh Cart" name="update" /></p> <p class="update-cart"><input type="submit" value="Refresh Cart" name="update" /></p>
<p class="go-checkout"><input type="submit" value="Proceed to Checkout" name="checkout" /></p> <p class="go-checkout"><input type="submit" value="Proceed to Checkout" name="checkout" /></p>
{% if additional_checkout_buttons %} {% if additional_checkout_buttons %}
<div class="additional-checkout-buttons"> <div class="additional-checkout-buttons">
@@ -62,73 +62,73 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
</form> </form>
{% endif %} {% endif %}
<h1 class="other-products"><span>Other Products You Might Enjoy</span></h1> <h1 class="other-products"><span>Other Products You Might Enjoy</span></h1>
<ul class="item-list clearfix"> <ul class="item-list clearfix">
{% for product in collections.frontpage.products limit:2 %} {% for product in collections.frontpage.products limit:2 %}
<li> <li>
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<div class="item-list-item"> <div class="item-list-item">
<div class="ili-top clearfix"> <div class="ili-top clearfix">
<div class="ili-top-content"> <div class="ili-top-content">
<h2><a href="{{product.url}}">{{product.title}}</a></h2> <h2><a href="{{product.url}}">{{product.title}}</a></h2>
<p>{{ product.description | truncatewords: 15 }}</p> <p>{{ product.description | truncatewords: 15 }}</p>
</div> </div>
<a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a> <a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a>
</div> </div>
<div class="ili-bottom clearfix"> <div class="ili-bottom clearfix">
<p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p> <p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p>
<input type="submit" class="" value="Add to Basket" /> <input type="submit" class="" value="Add to Basket" />
<p> <p>
<a href="{{product.url}}">View Details</a> <a href="{{product.url}}">View Details</a>
<span> <span>
{% if product.compare_at_price %} {% if product.compare_at_price %}
{% if product.price_min != product.compare_at_price %} {% if product.price_min != product.compare_at_price %}
{{product.compare_at_price | money}} - {{product.compare_at_price | money}} -
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong> <strong>
{{product.price_min | money}} {{product.price_min | money}}
</strong> </strong>
</span> </span>
</p> </p>
</div> </div>
</div> </div>
</form> </form>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
<div id="three-reasons" class="clearfix"> <div id="three-reasons" class="clearfix">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bit encrypted.</p> <p>Checkout is 256bit encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<!-- end page --> <!-- end page -->

View File

@@ -1,70 +1,70 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<h1>{{ collection.title }}</h1> <h1>{{ collection.title }}</h1>
{% if collection.description.size > 0 %} {% if collection.description.size > 0 %}
<div class="latest-news">{{ collection.description }}</div> <div class="latest-news">{{ collection.description }}</div>
{% endif %} {% endif %}
{% paginate collection.products by 8 %} {% paginate collection.products by 8 %}
<ul class="item-list clearfix"> <ul class="item-list clearfix">
{% for product in collection.products %} {% for product in collection.products %}
<li> <li>
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<div class="item-list-item"> <div class="item-list-item">
<div class="ili-top clearfix"> <div class="ili-top clearfix">
<div class="ili-top-content"> <div class="ili-top-content">
<h2><a href="{{product.url}}">{{product.title}}</a></h2> <h2><a href="{{product.url}}">{{product.title}}</a></h2>
<p>{{ product.description | truncatewords: 15 }}</p> <p>{{ product.description | truncatewords: 15 }}</p>
</div> </div>
<a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a> <a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a>
</div> </div>
<div class="ili-bottom clearfix"> <div class="ili-bottom clearfix">
<p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p> <p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p>
<input type="submit" class="" value="Add to Basket" /> <input type="submit" class="" value="Add to Basket" />
<p> <p>
<a href="{{product.url}}">View Details</a> <a href="{{product.url}}">View Details</a>
<span> <span>
{% if product.compare_at_price %} {% if product.compare_at_price %}
{% if product.price_min != product.compare_at_price %} {% if product.price_min != product.compare_at_price %}
{{product.compare_at_price | money}} - {{product.compare_at_price | money}} -
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong> <strong>
{{product.price_min | money}} {{product.price_min | money}}
</strong> </strong>
</span> </span>
</p> </p>
</div> </div>
</div> </div>
</form> </form>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
<div class="paginate clearfix"> <div class="paginate clearfix">
{{ paginate | default_pagination }} {{ paginate | default_pagination }}
</div> </div>
<div id="three-reasons" class="clearfix"> <div id="three-reasons" class="clearfix">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bit encrypted.</p> <p>Checkout is 256bit encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
{% endpaginate %} {% endpaginate %}

View File

@@ -1,94 +1,94 @@
<div id="gwrap"> <div id="gwrap">
<div id="gbox"> <div id="gbox">
<h1>Three Great Reasons You Should Shop With Us...</h1> <h1>Three Great Reasons You Should Shop With Us...</h1>
<ul> <ul>
<li class="gbox1"> <li class="gbox1">
<h2>Free Shipping</h2> <h2>Free Shipping</h2>
<p>On all orders over $25</p> <p>On all orders over $25</p>
</li> </li>
<li class="gbox2"> <li class="gbox2">
<h2>Top Quality</h2> <h2>Top Quality</h2>
<p>Hand made in our shop</p> <p>Hand made in our shop</p>
</li> </li>
<li class="gbox3"> <li class="gbox3">
<h2>100% Guarantee</h2> <h2>100% Guarantee</h2>
<p>Any time, any reason</p> <p>Any time, any reason</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<div id="page" class="clearfix"> <div id="page" class="clearfix">
<div class="latest-news">{{pages.alert.content}}</div> <div class="latest-news">{{pages.alert.content}}</div>
<ul class="item-list clearfix"> <ul class="item-list clearfix">
{% for product in collections.frontpage.products %} {% for product in collections.frontpage.products %}
<li> <li>
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<div class="item-list-item"> <div class="item-list-item">
<div class="ili-top clearfix"> <div class="ili-top clearfix">
<div class="ili-top-content"> <div class="ili-top-content">
<h2><a href="{{product.url}}">{{product.title}}</a></h2> <h2><a href="{{product.url}}">{{product.title}}</a></h2>
{{ product.description | truncatewords: 15 }}</p> <!-- extra cloding <p> tag for truncation --> {{ product.description | truncatewords: 15 }}</p> <!-- extra cloding <p> tag for truncation -->
</div> </div>
<a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a> <a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a>
</div> </div>
<div class="ili-bottom clearfix"> <div class="ili-bottom clearfix">
<p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p> <p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p>
<input type="submit" class="" value="Add to Basket" /> <input type="submit" class="" value="Add to Basket" />
<p> <p>
<a href="{{product.url}}">View Details</a> <a href="{{product.url}}">View Details</a>
<span> <span>
{% if product.compare_at_price %} {% if product.compare_at_price %}
{% if product.price_min != product.compare_at_price %} {% if product.price_min != product.compare_at_price %}
{{product.compare_at_price | money}} - {{product.compare_at_price | money}} -
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong> <strong>
{{product.price_min | money}} {{product.price_min | money}}
</strong> </strong>
</span> </span>
</p> </p>
</div> </div>
</div> </div>
</form> </form>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
<div id="one-two"> <div id="one-two">
<div id="two"> <div id="two">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-b"> <li class="two-b">
<h4>Save Energy</h4> <h4>Save Energy</h4>
<p>We're green, all the way.</p> <p>We're green, all the way.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bits encrypted.</p> <p>Checkout is 256bits encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
<div id="one"> <div id="one">
<h3>Our Company</h3> <h3>Our Company</h3>
{{pages.about-us.content | truncatewords: 49}} <a href="/pages/about-us">read more</a></p> {{pages.about-us.content | truncatewords: 49}} <a href="/pages/about-us">read more</a></p>
</div> </div>
</div> </div>
</div> </div>
<!-- end page --> <!-- end page -->

View File

@@ -1,56 +1,56 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<div id="text-page"> <div id="text-page">
<div class="entry"> <div class="entry">
<h1>{{page.title}}</h1> <h1>{{page.title}}</h1>
<div class="entry-post"> <div class="entry-post">
{{page.content}} {{page.content}}
</div> </div>
</div> </div>
</div> </div>
<h1>Featured Products</h1> <h1>Featured Products</h1>
<ul class="item-list clearfix"> <ul class="item-list clearfix">
{% for product in collections.frontpage.products %} {% for product in collections.frontpage.products %}
<li> <li>
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<div class="item-list-item"> <div class="item-list-item">
<div class="ili-top clearfix"> <div class="ili-top clearfix">
<div class="ili-top-content"> <div class="ili-top-content">
<h2><a href="{{product.url}}">{{product.title}}</a></h2> <h2><a href="{{product.url}}">{{product.title}}</a></h2>
<p>{{ product.description | truncatewords: 15 }}</p> <p>{{ product.description | truncatewords: 15 }}</p>
</div> </div>
<a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a> <a href="{{product.url}}" class="ili-top-image"><img src="{{ product.featured_image | product_img_url: 'small' }}" alt="{{ product.title | escape }}"/></a>
</div> </div>
<div class="ili-bottom clearfix"> <div class="ili-bottom clearfix">
<p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p> <p class="hiddenvariants" style="display: none">{% for variant in product.variants %}<span><input type="radio" name="id" value="{{variant.id}}" id="radio_{{variant.id}}" style="vertical-align: middle;" {%if forloop.first%} checked="checked" {%endif%} /><label for="radio_{{variant.id}}">{{ variant.price | money_with_currency }} - {{ variant.title }}</label></span>{% endfor %}</p>
<input type="submit" class="" value="Add to Basket" /> <input type="submit" class="" value="Add to Basket" />
<p> <p>
<a href="{{product.url}}">View Details</a> <a href="{{product.url}}">View Details</a>
<span> <span>
{% if product.compare_at_price %} {% if product.compare_at_price %}
{% if product.price_min != product.compare_at_price %} {% if product.price_min != product.compare_at_price %}
{{product.compare_at_price | money}} - {{product.compare_at_price | money}} -
{% endif %} {% endif %}
{% endif %} {% endif %}
<strong> <strong>
{{product.price_min | money}} {{product.price_min | money}}
</strong> </strong>
</span> </span>
</p> </p>
</div> </div>
</div> </div>
</form> </form>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<!-- end page --> <!-- end page -->

View File

@@ -1,90 +1,90 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<h1>{{ collection.title }} {{ product.title }}</h1> <h1>{{ collection.title }} {{ product.title }}</h1>
<p class="latest-news"><strong>Product Tags: </strong> <p class="latest-news"><strong>Product Tags: </strong>
{% for tag in product.tags %} {% for tag in product.tags %}
<a href="/collections/all/{{ tag }}">{{ tag }}</a> | <a href="/collections/all/{{ tag }}">{{ tag }}</a> |
{% endfor %} {% endfor %}
</p> </p>
<div class="product clearfix"> <div class="product clearfix">
<div class="product-info"> <div class="product-info">
<h1>{{ product.title }}</h1> <h1>{{ product.title }}</h1>
<div class="product-info-description"> <div class="product-info-description">
<p>{{ product.description }} </p> <p>{{ product.description }} </p>
</div> </div>
{% if product.available %} {% if product.available %}
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<h2>Product Options:</h2> <h2>Product Options:</h2>
<select id="product-info-options" name="id" class="product-info-options"> <select id="product-info-options" name="id" class="product-info-options">
{% for variant in product.variants %} {% for variant in product.variants %}
<option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option> <option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option>
{% endfor %} {% endfor %}
</select> </select>
<div id="price-field"></div> <div id="price-field"></div>
<div class="product-purchase-btn"> <div class="product-purchase-btn">
<input type="submit" class="add-this-to-cart" id="add-this-to-cart" value="Add to Basket" /> <input type="submit" class="add-this-to-cart" id="add-this-to-cart" value="Add to Basket" />
</div> </div>
</form> </form>
{% else %} {% else %}
<h2>Sold out!</h2> <h2>Sold out!</h2>
<p>Sorry, we're all out of this product. Check back often and order when it returns</p> <p>Sorry, we're all out of this product. Check back often and order when it returns</p>
{% endif %} {% endif %}
</div> </div>
<div class="product-images clearfix"> <div class="product-images clearfix">
{% for image in product.images %} {% for image in product.images %}
{% if forloop.first %} {% if forloop.first %}
<div class="product-image-large"> <div class="product-image-large">
<img src="{{ image | product_img_url: 'medium'}}" alt="{{product.title | escape }}" /> <img src="{{ image | product_img_url: 'medium'}}" alt="{{product.title | escape }}" />
</div> </div>
{% else %} {% else %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
<ul class="product-thumbs clearfix"> <ul class="product-thumbs clearfix">
{% for image in product.images %} {% for image in product.images %}
{% if forloop.first %} {% if forloop.first %}
{% else %} {% else %}
<li> <li>
<a href="{{ image | product_img_url: 'large' }}" class="product-thumbs" rel="lightbox[product]" title=""> <a href="{{ image | product_img_url: 'large' }}" class="product-thumbs" rel="lightbox[product]" title="">
<img src="{{ image | product_img_url: 'small'}}" alt="{{product.title | escape }}" /> <img src="{{ image | product_img_url: 'small'}}" alt="{{product.title | escape }}" />
</a> </a>
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
</div> </div>
<div id="three-reasons" class="clearfix"> <div id="three-reasons" class="clearfix">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bit encrypted.</p> <p>Checkout is 256bit encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
<!-- end page --> <!-- end page -->

View File

@@ -2,50 +2,50 @@
<div id="page" class="innerpage clearfix"> <div id="page" class="innerpage clearfix">
<h1>Search Results</h1> <h1>Search Results</h1>
{% if search.performed %} {% if search.performed %}
{% paginate search.results by 10 %} {% paginate search.results by 10 %}
{% if search.results == empty %} {% if search.results == empty %}
<div class="latest-news">Your search for "{{search.terms | escape}}" did not yield any results</div> <div class="latest-news">Your search for "{{search.terms | escape}}" did not yield any results</div>
{% else %} {% else %}
<ul class="search-list clearfix"> <ul class="search-list clearfix">
{% for item in search.results %} {% for item in search.results %}
<li> <li>
<h3 class="stitle">{{ item.title | link_to: item.url }}</h3> <h3 class="stitle">{{ item.title | link_to: item.url }}</h3>
<p class="sinfo">{{ item.content | strip_html | truncatewords: 65 | highlight: search.terms }} ... <a href="{{item.url}}" title="">view this item</a></p> <p class="sinfo">{{ item.content | strip_html | truncatewords: 65 | highlight: search.terms }} ... <a href="{{item.url}}" title="">view this item</a></p>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
<div class="paginate clearfix"> <div class="paginate clearfix">
{{ paginate | default_pagination }} {{ paginate | default_pagination }}
</div> </div>
<div id="three-reasons" class="clearfix"> <div id="three-reasons" class="clearfix">
<h3>Why Shop With Us?</h3> <h3>Why Shop With Us?</h3>
<ul> <ul>
<li class="two-a"> <li class="two-a">
<h4>24 Hours</h4> <h4>24 Hours</h4>
<p>We're always here to help.</p> <p>We're always here to help.</p>
</li> </li>
<li class="two-c"> <li class="two-c">
<h4>No Spam</h4> <h4>No Spam</h4>
<p>We'll never share your info.</p> <p>We'll never share your info.</p>
</li> </li>
<li class="two-d"> <li class="two-d">
<h4>Secure Servers</h4> <h4>Secure Servers</h4>
<p>Checkout is 256bit encrypted.</p> <p>Checkout is 256bit encrypted.</p>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
{% endpaginate %} {% endpaginate %}
{% endif %} {% endif %}

View File

@@ -2,15 +2,15 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<title>{{shop.name}} - {{page_title}}</title> <title>{{shop.name}} - {{page_title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
{{ 'reset.css' | asset_url | stylesheet_tag }} {{ 'reset.css' | asset_url | stylesheet_tag }}
{{ 'style.css' | asset_url | stylesheet_tag }} {{ 'style.css' | asset_url | stylesheet_tag }}
{{ 'lightbox.css' | asset_url | stylesheet_tag }} {{ 'lightbox.css' | asset_url | stylesheet_tag }}
{{ 'prototype/1.6/prototype.js' | global_asset_url | script_tag }} {{ 'prototype/1.6/prototype.js' | global_asset_url | script_tag }}
{{ 'scriptaculous/1.8.2/scriptaculous.js' | global_asset_url | script_tag }} {{ 'scriptaculous/1.8.2/scriptaculous.js' | global_asset_url | script_tag }}
{{ 'lightbox.js' | asset_url | script_tag }} {{ 'lightbox.js' | asset_url | script_tag }}
{{ 'option_selection.js' | shopify_asset_url | script_tag }} {{ 'option_selection.js' | shopify_asset_url | script_tag }}
{{ content_for_header }} {{ content_for_header }}
@@ -19,70 +19,70 @@
<div id="wrap"> <div id="wrap">
<div id="top"> <div id="top">
<div id="cart"> <div id="cart">
<h3>Shopping Cart</h3> <h3>Shopping Cart</h3>
<p class="cart-count"> <p class="cart-count">
{% if cart.item_count == 0 %} {% if cart.item_count == 0 %}
Your cart is currently empty Your cart is currently empty
{% else %} {% else %}
{{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} <span>-</span> Total: {{cart.total_price | money_with_currency }} <span>-</span> <a href="/cart">View Cart</a> {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }} <span>-</span> Total: {{cart.total_price | money_with_currency }} <span>-</span> <a href="/cart">View Cart</a>
{% endif %} {% endif %}
</p> </p>
</div> </div>
<div id="site-title"> <div id="site-title">
<h3><a href="/">{{shop.name}}</a></h3> <h3><a href="/">{{shop.name}}</a></h3>
<h4><span>Tribble: A Shopify Theme</span></h4> <h4><span>Tribble: A Shopify Theme</span></h4>
</div> </div>
</div> </div>
<ul id="nav"> <ul id="nav">
{% for link in linklists.main-menu.links %} {% for link in linklists.main-menu.links %}
<li>{{ link.title | link_to: link.url }}</li> <li>{{ link.title | link_to: link.url }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
{{ content_for_layout }} {{ content_for_layout }}
<div id="foot" class="clearfix"> <div id="foot" class="clearfix">
<div class="quick-links"> <div class="quick-links">
<h4>Quick Navigation</h4> <h4>Quick Navigation</h4>
<ul class="clearfix"> <ul class="clearfix">
<li><a href="/">Home</a></li> <li><a href="/">Home</a></li>
<li><a href="#top">Back to top</a></li> <li><a href="#top">Back to top</a></li>
{% for link in linklists.main-menu.links %} {% for link in linklists.main-menu.links %}
<li>{{ link.title | link_to: link.url }}</li> <li>{{ link.title | link_to: link.url }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
<div class="quick-contact"> <div class="quick-contact">
<h4>Quick Contact</h4> <h4>Quick Contact</h4>
<div class="vcard"> <div class="vcard">
<div class="org fn"> <div class="org fn">
<div class="organization-name">Really Great Widget Co.</div> <div class="organization-name">Really Great Widget Co.</div>
</div> </div>
<div class="adr"> <div class="adr">
<span class="street-address">2531 Barrington Court</span> <span class="street-address">2531 Barrington Court</span>
<span class="locality">Hayward</span>, <span class="locality">Hayward</span>,
<abbr title="California" class="region">CA</abbr> <abbr title="California" class="region">CA</abbr>
<span class="postal-code">94545</span> <span class="postal-code">94545</span>
</div> </div>
<a class="email" href="mailto:email@myshopifysite.com"> <a class="email" href="mailto:email@myshopifysite.com">
email@myshopifysite.com email@myshopifysite.com
</a> </a>
<div class="tel"> <div class="tel">
<span class="type">Support:</span> <span class="value">800-555-9954</span> <span class="type">Support:</span> <span class="value">800-555-9954</span>
</div> </div>
</div> </div>
</div> </div>
<p><a href="http://shopify.com" class="we-made">Powered by Shopify</a> &copy; Copyright {{ "now" | date: "%Y" }} {{ shop.name }}, All Rights Reserved. <a href="/blogs/news.xml" id="foot-rss">RSS Feed</a></p> <p><a href="http://shopify.com" class="we-made">Powered by Shopify</a> &copy; Copyright {{ "now" | date: "%Y" }} {{ shop.name }}, All Rights Reserved. <a href="/blogs/news.xml" id="foot-rss">RSS Feed</a></p>
</div> </div>
</div> </div>

View File

@@ -18,10 +18,10 @@
{{ comment.content }} {{ comment.content }}
</div> </div>
<div class="comment-details"> <div class="comment-details">
Posted by {{ comment.author }} on {{ comment.created_at | date: "%B %d, %Y" }} Posted by {{ comment.author }} on {{ comment.created_at | date: "%B %d, %Y" }}
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>

View File

@@ -1,17 +1,17 @@
<h1>Shopping Cart</h1> <h1>Shopping Cart</h1>
{% if cart.item_count == 0 %} {% if cart.item_count == 0 %}
<p><strong>Your shopping basket is empty.</strong> Perhaps a featured item below is of interest...</p> <p><strong>Your shopping basket is empty.</strong> Perhaps a featured item below is of interest...</p>
<table id="gallery"> <table id="gallery">
{% tablerow product in collections.frontpage.products cols: 3 limit: 12 %} {% tablerow product in collections.frontpage.products cols: 3 limit: 12 %}
<div class="gallery-image"> <div class="gallery-image">
<a href="{{ product.url | within: collections.frontpage }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 | escape }}"><img src="{{ product.images.first | product_img_url: 'medium' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ product.url | within: collections.frontpage }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 | escape }}"><img src="{{ product.images.first | product_img_url: 'medium' }}" alt="{{ product.title | escape }}" /></a>
</div> </div>
<div class="gallery-info"> <div class="gallery-info">
<a href="{{ product.url | within: collections.frontpage }}">{{ product.title | truncate: 30 }}</a><br /> <a href="{{ product.url | within: collections.frontpage }}">{{ product.title | truncate: 30 }}</a><br />
<small>{{ product.price | money }}{% if product.compare_at_price_max > product.price %} <del>{{ product.compare_at_price_max | money }}</del>{% endif %}</small> <small>{{ product.price | money }}{% if product.compare_at_price_max > product.price %} <del>{{ product.compare_at_price_max | money }}</del>{% endif %}</small>
</div> </div>
{% endtablerow %} {% endtablerow %}
</table> </table>
{% else %} {% else %}
<script type="text/javascript"> <script type="text/javascript">
function remove_item(id) { function remove_item(id) {
@@ -20,39 +20,39 @@
} }
</script> </script>
<form action="/cart" method="post" id="cartform"> <form action="/cart" method="post" id="cartform">
<table id="basket"> <table id="basket">
<tr> <tr>
<th>Item Description</th> <th>Item Description</th>
<th>Price</th> <th>Price</th>
<th>Qty</th> <th>Qty</th>
<th>Delete</th> <th>Delete</th>
<th>Total</th> <th>Total</th>
</tr>{% for item in cart.items %} </tr>{% for item in cart.items %}
<tr class="basket-{% cycle 'odd', 'even' %}"> <tr class="basket-{% cycle 'odd', 'even' %}">
<td class="basket-column-one"> <td class="basket-column-one">
<div class="basket-images"> <div class="basket-images">
<a href="{{ item.product.url }}" title="{{ item.title | escape }} &mdash; {{ item.product.description | strip_html | truncate: 50 | escape }}"><img src="{{ item.product.images.first | product_img_url: 'thumb' }}" alt="{{ item.title | escape }}" /></a> <a href="{{ item.product.url }}" title="{{ item.title | escape }} &mdash; {{ item.product.description | strip_html | truncate: 50 | escape }}"><img src="{{ item.product.images.first | product_img_url: 'thumb' }}" alt="{{ item.title | escape }}" /></a>
</div> </div>
<div class="basket-desc"> <div class="basket-desc">
<p><a href="{{ item.product.url }}">{{ item.title }}</a></p> <p><a href="{{ item.product.url }}">{{ item.title }}</a></p>
{{ item.product.description | strip_html | truncate: 120 }} {{ item.product.description | strip_html | truncate: 120 }}
</div> </div>
</td> </td>
<td class="basket-column">{{ item.price | money }}{% if item.variant.compare_at_price > item.price %}<br /><del>{{ item.variant.compare_at_price | money }}</del>{% endif %}</td> <td class="basket-column">{{ item.price | money }}{% if item.variant.compare_at_price > item.price %}<br /><del>{{ item.variant.compare_at_price | money }}</del>{% endif %}</td>
<td class="basket-column"><input type="text" size="4" name="updates[{{item.variant.id}}]" id="updates_{{ item.variant.id }}" value="{{ item.quantity }}" onfocus="this.select();"/></td> <td class="basket-column"><input type="text" size="4" name="updates[{{item.variant.id}}]" id="updates_{{ item.variant.id }}" value="{{ item.quantity }}" onfocus="this.select();"/></td>
<td class="basket-column"><a href="#" onclick="remove_item({{ item.variant.id }}); return false;">Remove</a></td> <td class="basket-column"><a href="#" onclick="remove_item({{ item.variant.id }}); return false;">Remove</a></td>
<td class="basket-column">{{ item.line_price | money }}</td> <td class="basket-column">{{ item.line_price | money }}</td>
</tr>{% endfor %} </tr>{% endfor %}
</table> </table>
<div id="basket-right"> <div id="basket-right">
<h3>Subtotal {{ cart.total_price | money }}</h3> <h3>Subtotal {{ cart.total_price | money }}</h3>
<input type="image" src="{{ 'update.png' | asset_url }}" id="update-cart" name="update" value="Update" /> <input type="image" src="{{ 'update.png' | asset_url }}" id="update-cart" name="update" value="Update" />
<input type="image" src="{{ 'checkout.png' | asset_url }}" name="checkout" value="Checkout" /> <input type="image" src="{{ 'checkout.png' | asset_url }}" name="checkout" value="Checkout" />
{% if additional_checkout_buttons %} {% if additional_checkout_buttons %}
<div class="additional-checkout-buttons"> <div class="additional-checkout-buttons">
<p>- or -</p> <p>- or -</p>
{{ content_for_additional_checkout_buttons }} {{ content_for_additional_checkout_buttons }}
</div> </div>
{% endif %} {% endif %}
</div> </div>
</form>{% endif %} </form>{% endif %}

View File

@@ -1,19 +1,19 @@
{% paginate collection.products by 12 %}{% if collection.products.size == 0 %} {% paginate collection.products by 12 %}{% if collection.products.size == 0 %}
<strong>No products found in this collection.</strong>{% else %} <strong>No products found in this collection.</strong>{% else %}
<h1>{{ collection.title }}</h1> <h1>{{ collection.title }}</h1>
{{ collection.description }} {{ collection.description }}
<table id="gallery"> <table id="gallery">
{% tablerow product in collection.products cols: 3 %} {% tablerow product in collection.products cols: 3 %}
<div class="gallery-image"> <div class="gallery-image">
<a href="{{ product.url | within: collection }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 | escape }}"><img src="{{ product.images.first | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ product.url | within: collection }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 | escape }}"><img src="{{ product.images.first | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a>
</div> </div>
<div class="gallery-info"> <div class="gallery-info">
<a href="{{ product.url | within: collection }}">{{ product.title | truncate: 30 }}</a><br /> <a href="{{ product.url | within: collection }}">{{ product.title | truncate: 30 }}</a><br />
<small>{{ product.price | money }}{% if product.compare_at_price_max > product.price %} <del>{{ product.compare_at_price_max | money }}</del>{% endif %}</small> <small>{{ product.price | money }}{% if product.compare_at_price_max > product.price %} <del>{{ product.compare_at_price_max | money }}</del>{% endif %}</small>
</div> </div>
{% endtablerow %} {% endtablerow %}
</table>{% if paginate.pages > 1 %} </table>{% if paginate.pages > 1 %}
<div id="paginate"> <div id="paginate">
{{ paginate | default_pagination }} {{ paginate | default_pagination }}
</div>{% endif %}{% endif %} </div>{% endif %}{% endif %}
{% endpaginate %} {% endpaginate %}

View File

@@ -1,22 +1,22 @@
<div id="about-excerpt"> <div id="about-excerpt">
{% assign article = pages.frontpage %} {% assign article = pages.frontpage %}
{% if article.content != "" %} {% if article.content != "" %}
<h2>{{ article.title }}</h2> <h2>{{ article.title }}</h2>
{{ article.content }} {{ article.content }}
{% else %} {% else %}
In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br /> In <em>Admin &gt; Blogs &amp; Pages</em>, create a page with the handle <strong><code>frontpage</code></strong> and it will show up here.<br />
{{ "Learn more about handles" | link_to "http://wiki.shopify.com/Handle" }} {{ "Learn more about handles" | link_to "http://wiki.shopify.com/Handle" }}
{% endif %} {% endif %}
</div> </div>
<table id="gallery"> <table id="gallery">
{% tablerow product in collections.frontpage.products cols: 3 limit: 12 %} {% tablerow product in collections.frontpage.products cols: 3 limit: 12 %}
<div class="gallery-image"> <div class="gallery-image">
<a href="{{ product.url | within: collections.frontpage }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 | escape }}"><img src="{{ product.images.first | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ product.url | within: collections.frontpage }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 | escape }}"><img src="{{ product.images.first | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a>
</div> </div>
<div class="gallery-info"> <div class="gallery-info">
<a href="{{ product.url | within: collections.frontpage }}">{{ product.title | truncate: 30 }}</a><br /> <a href="{{ product.url | within: collections.frontpage }}">{{ product.title | truncate: 30 }}</a><br />
<small>{{ product.price | money }}{% if product.compare_at_price_max > product.price %} <del>{{ product.compare_at_price_max | money }}</del>{% endif %}</small> <small>{{ product.price | money }}{% if product.compare_at_price_max > product.price %} <del>{{ product.compare_at_price_max | money }}</del>{% endif %}</small>
</div> </div>
{% endtablerow %} {% endtablerow %}
</table> </table>

View File

@@ -1,3 +1,3 @@
<h1>{{ page.title }}</h1> <h1>{{ page.title }}</h1>
{{ page.content }} {{ page.content }}

View File

@@ -1,19 +1,19 @@
<div id="product-left"> <div id="product-left">
{% for image in product.images %}{% if forloop.first %}<div id="product-image"> {% for image in product.images %}{% if forloop.first %}<div id="product-image">
<a href="{{ image | product_img_url: 'large' }}" rel="lightbox[images]" title="{{ product.title | escape }}"><img src="{{ image | product_img_url: 'medium' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ image | product_img_url: 'large' }}" rel="lightbox[images]" title="{{ product.title | escape }}"><img src="{{ image | product_img_url: 'medium' }}" alt="{{ product.title | escape }}" /></a>
</div>{% else %} </div>{% else %}
<div class="product-images"> <div class="product-images">
<a href="{{ image | product_img_url: 'large' }}" rel="lightbox[images]" title="{{ product.title | escape }}"><img src="{{ image | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ image | product_img_url: 'large' }}" rel="lightbox[images]" title="{{ product.title | escape }}"><img src="{{ image | product_img_url: 'small' }}" alt="{{ product.title | escape }}" /></a>
</div>{% endif %}{% endfor %} </div>{% endif %}{% endfor %}
</div> </div>
<div id="product-right"> <div id="product-right">
<h1>{{ product.title }}</h1> <h1>{{ product.title }}</h1>
{{ product.description }} {{ product.description }}
{% if product.available %} {% if product.available %}
<form action="/cart/add" method="post"> <form action="/cart/add" method="post">
<div id="product-variants"> <div id="product-variants">
<div id="price-field"></div> <div id="price-field"></div>
<select id="product-select" name='id'> <select id="product-select" name='id'>
@@ -21,18 +21,18 @@
<option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option> <option value="{{ variant.id }}">{{ variant.title }} - {{ variant.price | money }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<input type="image" src="{{ 'purchase.png' | asset_url }}" name="add" value="Purchase" id="purchase" /> <input type="image" src="{{ 'purchase.png' | asset_url }}" name="add" value="Purchase" id="purchase" />
</form> </form>
{% else %} {% else %}
<p class="bold-red">This product is temporarily unavailable</p> <p class="bold-red">This product is temporarily unavailable</p>
{% endif %} {% endif %}
<div id="product-details"> <div id="product-details">
<strong>Continue Shopping</strong><br /> <strong>Continue Shopping</strong><br />
Browse more {{ product.type | link_to_type }} or additional {{ product.vendor | link_to_vendor }} products. Browse more {{ product.type | link_to_type }} or additional {{ product.vendor | link_to_vendor }} products.
</div> </div>
</div> </div>

View File

@@ -22,100 +22,100 @@
<body id="page-{{ template }}"> <body id="page-{{ template }}">
<div id="header"> <div id="header">
<div class="container"> <div class="container">
<div id="logo"> <div id="logo">
<h1><a href="/" title="{{ shop.name }}">{{ shop.name }}</a></h1> <h1><a href="/" title="{{ shop.name }}">{{ shop.name }}</a></h1>
</div> </div>
<div id="navigation"> <div id="navigation">
<ul id="navigate"> <ul id="navigate">
<li><a href="/cart">View Cart</a></li> <li><a href="/cart">View Cart</a></li>
{% for link in linklists.main-menu.links reversed %} {% for link in linklists.main-menu.links reversed %}
<li><a href="{{ link.url }}">{{ link.title }}</a></li> <li><a href="{{ link.url }}">{{ link.title }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
<div id="mini-header"> <div id="mini-header">
<div class="container"> <div class="container">
<div id="shopping-cart"> <div id="shopping-cart">
<a href="/cart">Your shopping cart contains {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}</a> <a href="/cart">Your shopping cart contains {{ cart.item_count }} {{ cart.item_count | pluralize: 'item', 'items' }}</a>
</div> </div>
<div id="search-box"> <div id="search-box">
<form action="/search" method="get"> <form action="/search" method="get">
<input type="text" name="q" id="q" /> <input type="text" name="q" id="q" />
<input type="image" src="{{ 'seek.png' | asset_url }}" value="Seek" onclick="this.parentNode.submit(); return false;" id="seek" /> <input type="image" src="{{ 'seek.png' | asset_url }}" value="Seek" onclick="this.parentNode.submit(); return false;" id="seek" />
</form> </form>
</div> </div>
</div> </div>
</div> </div>
<div id="layout"> <div id="layout">
<div class="container"> <div class="container">
<div id="layout-left" {% if template != "cart" %}{% if template != "product" %}style="width:619px"{% endif %}{% endif %}>{% if template == "search" %} <div id="layout-left" {% if template != "cart" %}{% if template != "product" %}style="width:619px"{% endif %}{% endif %}>{% if template == "search" %}
<h1>Search Results</h1>{% endif %} <h1>Search Results</h1>{% endif %}
{{ content_for_layout }} {{ content_for_layout }}
</div>{% if template != "cart" %}{% if template != "product" %} </div>{% if template != "cart" %}{% if template != "product" %}
<div id="layout-right"> <div id="layout-right">
{% if template == "index" %} {% if template == "index" %}
{% if blogs.news.articles.size > 1 %} {% if blogs.news.articles.size > 1 %}
<a href="{{ shop.url }}/blogs/news.xml"><img src="{{ 'feed.png' | asset_url }}" alt="Subscribe" class="feed" /></a> <a href="{{ shop.url }}/blogs/news.xml"><img src="{{ 'feed.png' | asset_url }}" alt="Subscribe" class="feed" /></a>
<h3><a href="/blogs/news">More news</a></h3> <h3><a href="/blogs/news">More news</a></h3>
<ul id="blogs">{% for article in blogs.news.articles limit: 6 offset: 1 %} <ul id="blogs">{% for article in blogs.news.articles limit: 6 offset: 1 %}
<li><a href="{{ article.url }}">{{ article.title | strip_html | truncate: 30 }}</a><br /> <li><a href="{{ article.url }}">{{ article.title | strip_html | truncate: 30 }}</a><br />
<small>{{ article.content | strip_html | truncatewords: 12 }}</small> <small>{{ article.content | strip_html | truncatewords: 12 }}</small>
</li>{% endfor %} </li>{% endfor %}
</ul> </ul>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if template == "collection" %} {% if template == "collection" %}
<h3>Collection Tags</h3> <h3>Collection Tags</h3>
<div id="tags">{% if collection.tags.size == 0 %} <div id="tags">{% if collection.tags.size == 0 %}
No tags found.{% else %} No tags found.{% else %}
<span class="tags">{% for tag in collection.tags %}{% if current_tags contains tag %} {{ tag | highlight_active_tag | link_to_remove_tag: tag }}{% else %} {{ tag | highlight_active_tag | link_to_add_tag: tag }}{% endif %}{% unless forloop.last %}, {% endunless %}{% endfor %}</span>{% endif %} <span class="tags">{% for tag in collection.tags %}{% if current_tags contains tag %} {{ tag | highlight_active_tag | link_to_remove_tag: tag }}{% else %} {{ tag | highlight_active_tag | link_to_add_tag: tag }}{% endif %}{% unless forloop.last %}, {% endunless %}{% endfor %}</span>{% endif %}
</div> </div>
{% endif %} {% endif %}
<h3>Navigation</h3> <h3>Navigation</h3>
<ul id="links"> <ul id="links">
{% for link in linklists.main-menu.links %} {% for link in linklists.main-menu.links %}
<li><a href="{{ link.url }}">{{ link.title }}</a></li> <li><a href="{{ link.url }}">{{ link.title }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
{% if template != "page" %} {% if template != "page" %}
<h3>Featured Products</h3> <h3>Featured Products</h3>
<ul id="featuring">{% for product in collections.frontpage.products limit: 6 %} <ul id="featuring">{% for product in collections.frontpage.products limit: 6 %}
<li class="featuring-list"> <li class="featuring-list">
<div class="featuring-image"> <div class="featuring-image">
<a href="{{ product.url | within: collections.frontpage }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 }}"><img src="{{ product.images.first | product_img_url: 'icon' }}" alt="{{ product.title | escape }}" /></a> <a href="{{ product.url | within: collections.frontpage }}" title="{{ product.title | escape }} &mdash; {{ product.description | strip_html | truncate: 50 }}"><img src="{{ product.images.first | product_img_url: 'icon' }}" alt="{{ product.title | escape }}" /></a>
</div> </div>
<div class="featuring-info"> <div class="featuring-info">
<a href="{{ product.url | within: collections.frontpage }}">{{ product.title | strip_html | truncate: 28 }}</a><br /> <a href="{{ product.url | within: collections.frontpage }}">{{ product.title | strip_html | truncate: 28 }}</a><br />
<small><span class="light">from</span> {{ product.price | money }}</small> <small><span class="light">from</span> {{ product.price | money }}</small>
</div> </div>
</li>{% endfor %} </li>{% endfor %}
</ul> </ul>
{% endif %} {% endif %}
</div>{% endif %}{% endif %} </div>{% endif %}{% endif %}
</div> </div>
</div> </div>
<div id="footer"> <div id="footer">
<div id="footer-fader"> <div id="footer-fader">
<div class="container"> <div class="container">
<div id="footer-right">{% for link in linklists.footer.links %} <div id="footer-right">{% for link in linklists.footer.links %}
{{ link.title | link_to: link.url }} {% unless forloop.last %}&#124;{% endunless %}{% endfor %} {{ link.title | link_to: link.url }} {% unless forloop.last %}&#124;{% endunless %}{% endfor %}
</div> </div>
<span id="footer-left"> <span id="footer-left">
Copyright &copy; {{ "now" | date: "%Y" }} <a href="/">{{ shop.name }}</a>. All Rights Reserved. All prices {{ shop.currency }}.<br /> Copyright &copy; {{ "now" | date: "%Y" }} <a href="/">{{ shop.name }}</a>. All Rights Reserved. All prices {{ shop.currency }}.<br />
This website is powered by <a href="http://www.shopify.com">Shopify</a>. This website is powered by <a href="http://www.shopify.com">Shopify</a>.
</span> </span>
</div> </div>
</div> </div>
</div> </div>
</body> </body>

View File

@@ -14,17 +14,6 @@ require File.dirname(__FILE__) + '/shopify/liquid'
require File.dirname(__FILE__) + '/shopify/database.rb' require File.dirname(__FILE__) + '/shopify/database.rb'
class ThemeRunner class ThemeRunner
class FileSystem
def initialize(path)
@path = path
end
# Called by Liquid to retrieve a template file
def read_template_file(template_path, context)
File.read(@path + '/' + template_path + '.liquid')
end
end
# Load all templates into memory, do this now so that # Load all templates into memory, do this now so that
# we don't profile IO. # we don't profile IO.
@@ -42,7 +31,6 @@ class ThemeRunner
# Dup assigns because will make some changes to them # Dup assigns because will make some changes to them
@tests.each do |liquid, layout, template_name| @tests.each do |liquid, layout, template_name|
tmpl = Liquid::Template.new tmpl = Liquid::Template.new
tmpl.parse(liquid) tmpl.parse(liquid)
tmpl = Liquid::Template.new tmpl = Liquid::Template.new
@@ -58,14 +46,14 @@ class ThemeRunner
# Compute page_tempalte outside of profiler run, uninteresting to profiler # Compute page_tempalte outside of profiler run, uninteresting to profiler
page_template = File.basename(template_name, File.extname(template_name)) page_template = File.basename(template_name, File.extname(template_name))
compile_and_render(liquid, layout, assigns, page_template, template_name) compile_and_render(liquid, layout, assigns, page_template)
end end
end end
def run_profile def run_profile
RubyProf.measure_mode = RubyProf::WALL_TIME RubyProf.measure_mode = RubyProf::PROCESS_TIME
# Dup assigns because will make some changes to them # Dup assigns because will make some changes to them
assigns = Database.tables.dup assigns = Database.tables.dup
@@ -85,7 +73,7 @@ class ThemeRunner
html = nil html = nil
RubyProf.resume RubyProf.resume
html = compile_and_render(liquid, layout, assigns, page_template, template_name) html = compile_and_render(liquid, layout, assigns, page_template)
RubyProf.pause RubyProf.pause
@@ -99,11 +87,10 @@ class ThemeRunner
RubyProf.stop RubyProf.stop
end end
def compile_and_render(template, layout, assigns, page_template, template_file) def compile_and_render(template, layout, assigns, page_template)
tmpl = Liquid::Template.new tmpl = Liquid::Template.new
tmpl.assigns['page_title'] = 'Page title' tmpl.assigns['page_title'] = 'Page title'
tmpl.assigns['template'] = page_template tmpl.assigns['template'] = page_template
tmpl.registers[:file_system] = ThemeRunner::FileSystem.new(File.dirname(template_file))
content_for_layout = tmpl.parse(template).render(assigns) content_for_layout = tmpl.parse(template).render(assigns)

View File

@@ -254,12 +254,16 @@ class ContextTest < Test::Unit::TestCase
@context['test'] = {'test' => [1,2,3,4,5]} @context['test'] = {'test' => [1,2,3,4,5]}
assert_equal 1, @context['test.test[0]'] assert_equal 1, @context['test.test[0]']
end
def test_recoursive_array_notation_for_hash
@context['test'] = [{'test' => 'worked'}] @context['test'] = [{'test' => 'worked'}]
assert_equal 'worked', @context['test[0].test'] assert_equal 'worked', @context['test[0].test']
end end
def test_hash_to_array_transition def test_hash_to_array_transition
@context['colors'] = { @context['colors'] = {
'Blue' => ['003366','336699', '6699CC', '99CCFF'], 'Blue' => ['003366','336699', '6699CC', '99CCFF'],
@@ -315,7 +319,7 @@ class ContextTest < Test::Unit::TestCase
@context['nested'] = {'var' => 'tags'} @context['nested'] = {'var' => 'tags'}
@context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] } @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
assert_equal 'deepsnow', @context['products[var].first'] #assert_equal 'deepsnow', @context['products[var].first']
assert_equal 'freestyle', @context['products[nested.var].last'] assert_equal 'freestyle', @context['products[nested.var].last']
end end

View File

@@ -71,34 +71,23 @@ class DropsTest < Test::Unit::TestCase
include Liquid include Liquid
def test_product_drop def test_product_drop
assert_nothing_raised do assert_nothing_raised do
tpl = Liquid::Template.parse( ' ' ) tpl = Liquid::Template.parse( ' ' )
tpl.render('product' => ProductDrop.new) tpl.render('product' => ProductDrop.new)
end end
end end
def test_drop_does_only_respond_to_whitelisted_methods
assert_equal "", Liquid::Template.parse("{{ product.inspect }}").render('product' => ProductDrop.new)
assert_equal "", Liquid::Template.parse("{{ product.pretty_inspect }}").render('product' => ProductDrop.new)
assert_equal "", Liquid::Template.parse("{{ product.whatever }}").render('product' => ProductDrop.new)
assert_equal "", Liquid::Template.parse('{{ product | map: "inspect" }}').render('product' => ProductDrop.new)
assert_equal "", Liquid::Template.parse('{{ product | map: "pretty_inspect" }}').render('product' => ProductDrop.new)
assert_equal "", Liquid::Template.parse('{{ product | map: "whatever" }}').render('product' => ProductDrop.new)
end
def test_drops_respond_to_to_liquid
assert_equal "text1", Liquid::Template.parse("{{ product.to_liquid.texts.text }}").render('product' => ProductDrop.new)
assert_equal "text1", Liquid::Template.parse('{{ product | map: "to_liquid" | map: "texts" | map: "text" }}').render('product' => ProductDrop.new)
end
def test_text_drop def test_text_drop
output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render('product' => ProductDrop.new) output = Liquid::Template.parse( ' {{ product.texts.text }} ' ).render('product' => ProductDrop.new)
assert_equal ' text1 ', output assert_equal ' text1 ', output
end end
def test_unknown_method def test_unknown_method
output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render('product' => ProductDrop.new) output = Liquid::Template.parse( ' {{ product.catchall.unknown }} ' ).render('product' => ProductDrop.new)
assert_equal ' method: unknown ', output assert_equal ' method: unknown ', output
end end
def test_integer_argument_drop def test_integer_argument_drop

View File

@@ -1,25 +0,0 @@
require 'test_helper'
module MoneyFilter
def money(input)
sprintf(' %d$ ', input)
end
end
module CanadianMoneyFilter
def money(input)
sprintf(' %d$ CAD ', input)
end
end
class HashOrderingTest < Test::Unit::TestCase
include Liquid
def test_global_register_order
Template.register_filter(MoneyFilter)
Template.register_filter(CanadianMoneyFilter)
assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, nil)
end
end

View File

@@ -0,0 +1,93 @@
require 'test_helper'
class ParserTest < Test::Unit::TestCase
include Liquid
def test_strings
assert_equal [[:id, "string"]], Parser.parse('"string"')
assert_equal [[:id, "string"]], Parser.parse('\'string\'')
end
def test_integer
assert_equal [[:id, 1]], Parser.parse('1')
assert_equal [[:id, 100001]], Parser.parse('100001')
end
def test_float
assert_equal [[:id, 1.1]], Parser.parse('1.1')
assert_equal [[:id, 1.55435]], Parser.parse('1.55435')
end
def test_null
assert_equal [[:id, nil]], Parser.parse('null')
assert_equal [[:id, nil]], Parser.parse('nil')
end
def test_bool
assert_equal [[:id, true]], Parser.parse('true')
assert_equal [[:id, false]], Parser.parse('false')
end
def test_ranges
assert_equal [[:id, 1], [:id, 5], [:range, nil]], Parser.parse('(1..5)')
assert_equal [[:id, 100], [:id, 500], [:range, nil]], Parser.parse('(100..500)')
end
def test_ranges_with_lookups
assert_equal [[:id, 1], [:id, "test"], [:lookup, nil], [:range, nil]], Parser.parse('(1..test)')
end
def test_lookups
assert_equal [[:id, "variable"], [:lookup, nil]], Parser.parse('variable')
assert_equal [[:id, "underscored_variable"], [:lookup, nil]], Parser.parse('underscored_variable')
assert_equal [[:id, "c"], [:lookup, nil]], Parser.parse('c')
end
def test_global_hash
assert_equal [[:id, true], [:lookup, nil]], Parser.parse('[true]')
assert_equal [[:id, "string"], [:lookup, nil]], Parser.parse('["string"]')
assert_equal [[:id, 5.55], [:lookup, nil]], Parser.parse('[5.55]')
assert_equal [[:id, 0], [:lookup, nil]], Parser.parse('[0]')
assert_equal [[:id, "variable"], [:lookup, nil], [:lookup, nil]], Parser.parse('[variable]')
end
def test_descent
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "variable2"], [:call, nil]], Parser.parse('variable1.variable2')
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "variable2"], [:call, nil], [:id, "variable3"], [:call, nil]], Parser.parse('variable1.variable2.variable3')
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "under_score"], [:call, nil]], Parser.parse('variable1.under_score')
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "question?"], [:call, nil]], Parser.parse('variable1.question?')
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "exclaimation!"], [:call, nil]], Parser.parse('variable1.exclaimation!')
end
def test_descent_hash
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "variable2"], [:call, nil]], Parser.parse('variable1["variable2"]')
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "variable2"], [:lookup, nil], [:call, nil]], Parser.parse('variable1[variable2]')
end
def test_buildin
assert_equal [[:id, "first"], [:lookup, nil]], Parser.parse('first')
assert_equal [[:id, "var"], [:lookup, nil], [:buildin, "first"]], Parser.parse('var.first')
assert_equal [[:id, "var"], [:lookup, nil], [:buildin, "last"]], Parser.parse('var.last')
assert_equal [[:id, "var"], [:lookup, nil], [:buildin, "size"]], Parser.parse('var.size')
end
def test_descent_hash_descent
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "test1"], [:lookup, nil], [:id, "test2"], [:call, nil], [:call, nil]],
Parser.parse('variable1[test1.test2]'), "resolove: variable1[test1.test2]"
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "test1"], [:lookup, nil], [:id, "test2"], [:call, nil], [:call, nil]],
Parser.parse('variable1[test1["test2"]]'), 'resolove: variable1[test1["test2"]]'
assert_equal [[:id, "variable1"], [:lookup, nil], [:id, "test1"], [:lookup, nil], [:id, "test2"], [:lookup, nil], [:call, nil], [:call, nil]],
Parser.parse('variable1[test1[test2]]'), "resolove: variable1[test1[test2]]"
end
end

View File

@@ -39,7 +39,7 @@ class ParsingQuirksTest < Test::Unit::TestCase
def test_meaningless_parens def test_meaningless_parens
assigns = {'b' => 'bar', 'c' => 'baz'} assigns = {'b' => 'bar', 'c' => 'baz'}
markup = "a == 'foo' or (b == 'bar' and c == 'baz') or false" markup = "a == 'foo' or b == 'bar' and c == 'baz' or false"
assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns) assert_template_result(' YES ',"{% if #{markup} %} YES {% endif %}", assigns)
end end

View File

@@ -1,32 +1,9 @@
# encoding: utf-8
require 'test_helper' require 'test_helper'
class Filters class Filters
include Liquid::StandardFilters include Liquid::StandardFilters
end end
class TestThing
def initialize
@foo = 0
end
def to_s
"woot: #{@foo}"
end
def to_liquid
@foo += 1
self
end
end
class TestDrop < Liquid::Drop
def test
"testfoo"
end
end
class StandardFiltersTest < Test::Unit::TestCase class StandardFiltersTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -60,7 +37,6 @@ class StandardFiltersTest < Test::Unit::TestCase
assert_equal '1234567890', @filters.truncate('1234567890', 20) assert_equal '1234567890', @filters.truncate('1234567890', 20)
assert_equal '...', @filters.truncate('1234567890', 0) assert_equal '...', @filters.truncate('1234567890', 0)
assert_equal '1234567890', @filters.truncate('1234567890') assert_equal '1234567890', @filters.truncate('1234567890')
assert_equal "测试...", @filters.truncate("测试测试测试测试", 5)
end end
def test_strip def test_strip
@@ -85,16 +61,12 @@ class StandardFiltersTest < Test::Unit::TestCase
assert_equal 'one two...', @filters.truncatewords('one two three', 2) assert_equal 'one two...', @filters.truncatewords('one two three', 2)
assert_equal 'one two three', @filters.truncatewords('one two three') assert_equal 'one two three', @filters.truncatewords('one two three')
assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15) assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15)
assert_equal "测试测试测试测试", @filters.truncatewords('测试测试测试测试', 5)
end end
def test_strip_html def test_strip_html
assert_equal 'test', @filters.strip_html("<div>test</div>") assert_equal 'test', @filters.strip_html("<div>test</div>")
assert_equal 'test', @filters.strip_html("<div id='test'>test</div>") assert_equal 'test', @filters.strip_html("<div id='test'>test</div>")
assert_equal '', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>") assert_equal '', @filters.strip_html("<script type='text/javascript'>document.write('some stuff');</script>")
assert_equal '', @filters.strip_html("<style type='text/css'>foo bar</style>")
assert_equal 'test', @filters.strip_html("<div\nclass='multiline'>test</div>")
assert_equal 'test', @filters.strip_html("<!-- foo bar \n test -->test")
assert_equal '', @filters.strip_html(nil) assert_equal '', @filters.strip_html(nil)
end end
@@ -108,33 +80,12 @@ class StandardFiltersTest < Test::Unit::TestCase
assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a") assert_equal [{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], @filters.sort([{"a" => 4}, {"a" => 3}, {"a" => 1}, {"a" => 2}], "a")
end end
def test_reverse
assert_equal [4,3,2,1], @filters.reverse([1,2,3,4])
end
def test_map def test_map
assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a') assert_equal [1,2,3,4], @filters.map([{"a" => 1}, {"a" => 2}, {"a" => 3}, {"a" => 4}], 'a')
assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}", assert_template_result 'abc', "{{ ary | map:'foo' | map:'bar' }}",
'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}] 'ary' => [{'foo' => {'bar' => 'a'}}, {'foo' => {'bar' => 'b'}}, {'foo' => {'bar' => 'c'}}]
end end
def test_map_doesnt_call_arbitrary_stuff
assert_equal "", Liquid::Template.parse('{{ "foo" | map: "__id__" }}').render
assert_equal "", Liquid::Template.parse('{{ "foo" | map: "inspect" }}').render
end
def test_map_calls_to_liquid
t = TestThing.new
assert_equal "woot: 1", Liquid::Template.parse('{{ foo }}').render("foo" => t)
end
def test_map_over_proc
drop = TestDrop.new
p = Proc.new{ drop }
templ = '{{ procs | map: "test" }}'
assert_equal "testfoo", Liquid::Template.parse(templ).render("procs" => [p])
end
def test_date def test_date
assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B") assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")
assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B") assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")
@@ -152,8 +103,6 @@ class StandardFiltersTest < Test::Unit::TestCase
assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y") assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")
assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y") assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 2004", "%m/%d/%Y")
assert_equal "#{Date.today.year}", @filters.date('now', '%Y')
assert_equal "#{Date.today.year}", @filters.date('today', '%Y')
assert_equal nil, @filters.date(nil, "%B") assert_equal nil, @filters.date(nil, "%B")
@@ -170,9 +119,9 @@ class StandardFiltersTest < Test::Unit::TestCase
end end
def test_replace def test_replace
assert_equal '2 2 2 2', @filters.replace('1 1 1 1', '1', 2) assert_equal 'b b b b', @filters.replace("a a a a", 'a', 'b')
assert_equal '2 1 1 1', @filters.replace_first('1 1 1 1', '1', 2) assert_equal 'b a a a', @filters.replace_first("a a a a", 'a', 'b')
assert_template_result '2 1 1 1', "{{ '1 1 1 1' | replace_first: '1', 2 }}" assert_template_result 'b a a a', "{{ 'a a a a' | replace_first: 'a', 'b' }}"
end end
def test_remove def test_remove
@@ -187,7 +136,6 @@ class StandardFiltersTest < Test::Unit::TestCase
def test_strip_newlines def test_strip_newlines
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc" assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\r\nb\nc"
end end
def test_newlines_to_br def test_newlines_to_br
@@ -212,8 +160,6 @@ class StandardFiltersTest < Test::Unit::TestCase
assert_match(/(6\.3)|(6\.(0{13})1)/, Template.parse("{{ '2.1' | times:3 }}").render) assert_match(/(6\.3)|(6\.(0{13})1)/, Template.parse("{{ '2.1' | times:3 }}").render)
assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}" assert_template_result "6", "{{ '2.1' | times:3 | replace: '.','-' | plus:0}}"
assert_template_result "7.25", "{{ 0.0725 | times:100 }}"
end end
def test_divided_by def test_divided_by
@@ -225,8 +171,6 @@ class StandardFiltersTest < Test::Unit::TestCase
assert_template_result "5", "{{ 15 | divided_by:3 }}" assert_template_result "5", "{{ 15 | divided_by:3 }}"
assert_template_result "Liquid error: divided by 0", "{{ 5 | divided_by:0 }}" assert_template_result "Liquid error: divided by 0", "{{ 5 | divided_by:0 }}"
assert_template_result "0.5", "{{ 2.0 | divided_by:4 }}"
end end
def test_modulo def test_modulo

View File

@@ -281,17 +281,4 @@ HERE
def test_blank_string_not_iterable def test_blank_string_not_iterable
assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '') assert_template_result('', "{% for char in characters %}I WILL NOT BE OUTPUT{% endfor %}", 'characters' => '')
end end
def test_bad_variable_naming_in_for_loop
assert_raise(Liquid::SyntaxError) do
Liquid::Template.parse('{% for a/b in x %}{% endfor %}')
end
end
def test_spacing_with_variable_naming_in_for_loop
expected = '12345'
template = '{% for item in items %}{{item}}{% endfor %}'
assigns = {'items' => [1,2,3,4,5]}
assert_template_result(expected, template, assigns)
end
end end

View File

@@ -157,10 +157,4 @@ class IfElseTagTest < Test::Unit::TestCase
assert_template_result('yes', assert_template_result('yes',
%({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %})) %({% if 'gnomeslab-and-or-liquid' contains 'gnomeslab-and-or-liquid' %}yes{% endif %}))
end end
def test_operators_are_whitelisted
assert_raise(SyntaxError) do
assert_template_result('', %({% if 1 or throw or or 1 %}yes{% endif %}))
end
end
end # IfElseTest end # IfElseTest

View File

@@ -39,15 +39,6 @@ class OtherFileSystem
end end
end end
class CountingFileSystem
attr_reader :count
def read_template_file(template_path, context)
@count ||= 0
@count += 1
'from CountingFileSystem'
end
end
class IncludeTagTest < Test::Unit::TestCase class IncludeTagTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -145,22 +136,4 @@ class IncludeTagTest < Test::Unit::TestCase
assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'}) assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'})
end end
def test_include_tag_caches_second_read_of_same_partial
file_system = CountingFileSystem.new
assert_equal 'from CountingFileSystemfrom CountingFileSystem',
Template.parse("{% include 'pick_a_source' %}{% include 'pick_a_source' %}").render({}, :registers => {:file_system => file_system})
assert_equal 1, file_system.count
end
def test_include_tag_doesnt_cache_partials_across_renders
file_system = CountingFileSystem.new
assert_equal 'from CountingFileSystem',
Template.parse("{% include 'pick_a_source' %}").render({}, :registers => {:file_system => file_system})
assert_equal 1, file_system.count
assert_equal 'from CountingFileSystem',
Template.parse("{% include 'pick_a_source' %}").render({}, :registers => {:file_system => file_system})
assert_equal 2, file_system.count
end
end # IncludeTagTest end # IncludeTagTest

View File

@@ -9,16 +9,7 @@ class RawTagTest < Test::Unit::TestCase
end end
def test_output_in_raw def test_output_in_raw
assert_template_result '{{ test }}', '{% raw %}{{ test }}{% endraw %}' assert_template_result '{{ test }}',
end '{% raw %}{{ test }}{% endraw %}'
def test_open_tag_in_raw
assert_template_result ' Foobar {% invalid ', '{% raw %} Foobar {% invalid {% endraw %}'
assert_template_result ' Foobar invalid %} ', '{% raw %} Foobar invalid %} {% endraw %}'
assert_template_result ' Foobar {{ invalid ', '{% raw %} Foobar {{ invalid {% endraw %}'
assert_template_result ' Foobar invalid }} ', '{% raw %} Foobar invalid }} {% endraw %}'
assert_template_result ' Foobar {% invalid {% {% endraw ', '{% raw %} Foobar {% invalid {% {% endraw {% endraw %}'
assert_template_result ' Foobar {% {% {% ', '{% raw %} Foobar {% {% {% {% endraw %}'
assert_template_result ' test {% raw %} {% endraw %}', '{% raw %} test {% raw %} {% {% endraw %}endraw %}'
end end
end end

View File

@@ -1,19 +1,5 @@
require 'test_helper' require 'test_helper'
class TemplateContextDrop < Liquid::Drop
def before_method(method)
method
end
def foo
'fizzbuzz'
end
def baz
@context.registers['lulz']
end
end
class TemplateTest < Test::Unit::TestCase class TemplateTest < Test::Unit::TestCase
include Liquid include Liquid
@@ -85,62 +71,4 @@ class TemplateTest < Test::Unit::TestCase
assert_equal '1', t.render(assigns) assert_equal '1', t.render(assigns)
@global = nil @global = nil
end end
def test_resource_limits_render_length
t = Template.parse("0123456789")
t.resource_limits = { :render_length_limit => 5 }
assert_equal "Liquid error: Memory limits exceeded", t.render()
assert t.resource_limits[:reached]
t.resource_limits = { :render_length_limit => 10 }
assert_equal "0123456789", t.render()
assert_not_nil t.resource_limits[:render_length_current]
end
def test_resource_limits_render_score
t = Template.parse("{% for a in (1..10) %} {% for a in (1..10) %} foo {% endfor %} {% endfor %}")
t.resource_limits = { :render_score_limit => 50 }
assert_equal "Liquid error: Memory limits exceeded", t.render()
assert t.resource_limits[:reached]
t = Template.parse("{% for a in (1..100) %} foo {% endfor %}")
t.resource_limits = { :render_score_limit => 50 }
assert_equal "Liquid error: Memory limits exceeded", t.render()
assert t.resource_limits[:reached]
t.resource_limits = { :render_score_limit => 200 }
assert_equal (" foo " * 100), t.render()
assert_not_nil t.resource_limits[:render_score_current]
end
def test_resource_limits_assign_score
t = Template.parse("{% assign foo = 42 %}{% assign bar = 23 %}")
t.resource_limits = { :assign_score_limit => 1 }
assert_equal "Liquid error: Memory limits exceeded", t.render()
assert t.resource_limits[:reached]
t.resource_limits = { :assign_score_limit => 2 }
assert_equal "", t.render()
assert_not_nil t.resource_limits[:assign_score_current]
end
def test_resource_limits_aborts_rendering_after_first_error
t = Template.parse("{% for a in (1..100) %} foo1 {% endfor %} bar {% for a in (1..100) %} foo2 {% endfor %}")
t.resource_limits = { :render_score_limit => 50 }
assert_equal "Liquid error: Memory limits exceeded", t.render()
assert t.resource_limits[:reached]
end
def test_resource_limits_hash_in_template_gets_updated_even_if_no_limits_are_set
t = Template.parse("{% for a in (1..100) %} {% assign foo = 1 %} {% endfor %}")
t.render()
assert t.resource_limits[:assign_score_current] > 0
assert t.resource_limits[:render_score_current] > 0
assert t.resource_limits[:render_length_current] > 0
end
def test_can_use_drop_as_context
t = Template.new
t.registers['lulz'] = 'haha'
drop = TemplateContextDrop.new
assert_equal 'fizzbuzz', t.parse('{{foo}}').render(drop)
assert_equal 'bar', t.parse('{{bar}}').render(drop)
assert_equal 'haha', t.parse("{{baz}}").render(drop)
end
end # TemplateTest end # TemplateTest

View File

@@ -113,12 +113,6 @@ class VariableTest < Test::Unit::TestCase
assert_equal 'hello', var.name assert_equal 'hello', var.name
assert_equal [['things',["greeting: \"world\"","farewell: 'goodbye'"]]], var.filters assert_equal [['things',["greeting: \"world\"","farewell: 'goodbye'"]]], var.filters
end end
def test_lax_filter_argument_parsing
var = Variable.new(%! number_of_comments | pluralize: 'comment': 'comments' !)
assert_equal 'number_of_comments', var.name
assert_equal [['pluralize',["'comment'","'comments'"]]], var.filters
end
end end