.idea
node_modules
+static--wiki--editor--node_modules*
/static_test
chromedriver.log
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
import os
from subprocess import call
from optparse import make_option
class Command(BaseCommand):
option_list = BaseCommand.option_list + (
- make_option('--node-bin-path',
+ make_option(
+ '--node-bin-path',
action='store',
dest='node_bin_path',
type='string',
default=None,
help='Path to node binary'),
- make_option('--npm-bin',
+ make_option(
+ '--npm-bin',
action='store',
dest='npm_bin',
type='string',
default='npm',
help='Path to npm binary'),
- make_option('--editor-npm-env',
+ make_option(
+ '--editor-npm-env',
action='store',
dest='editor_npm_env',
type='string',
default=None,
help='Destination path of npm environment, defaults to ./node_modules'),
- make_option('--editor-optimize',
+ make_option(
+ '--editor-optimize',
action='store',
dest='editor_optimize',
type='string',
assert os.path.isdir(npm_env)
os.symlink(npm_env, os.path.join(rng_base_dir, 'node_modules'))
try:
- call([options['npm_bin'], 'install'], cwd = rng_base_dir)
+ call([options['npm_bin'], 'install'], cwd=rng_base_dir)
except OSError:
raise CommandError('Something went wrong, propably npm binary not found. Tried: %s' % options['npm_bin'])
if options['node_bin_path']:
# grunt needs npm binary to be foundable in PATH
os.environ['PATH'] = '%s:%s' % (options['node_bin_path'], os.environ['PATH'])
- args = ['./node_modules/.bin/grunt', 'build', '--output-dir=%s' % build_dir]
+ args = ['./node_modules/.bin/grunt', 'build', '--output-dir=%s' % build_dir]
if options['editor_optimize']:
args.append('--optimize=%s' % options['editor_optimize'])
- call(args, cwd = rng_base_dir)
+ self.stdout.write('Calling %s at %s' % (' '.join(args), rng_base_dir))
+ call(args, cwd=rng_base_dir)
- call_command('collectstatic', interactive = False, ignore_patterns = ['editor'])
+ call_command('collectstatic', interactive=False, ignore_patterns=['editor'])
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.contrib import admin
from catalogue import models
# -*- coding: utf-8 -*-
-from StringIO import StringIO
-#from catalogue.models import Book
-#from librarian import DocProvider
from django.http import HttpResponse
-#~ class RedakcjaDocProvider(DocProvider):
- #~ """Used for getting books' children."""
-#~
- #~ def __init__(self, publishable):
- #~ self.publishable = publishable
-#~
- #~ def by_slug(self, slug):
- #~ return StringIO(Book.objects.get(dc_slug=slug
- #~ ).materialize(publishable=self.publishable
- #~ ).encode('utf-8'))
-
-
def serve_file(file_path, name, mime_type):
def read_chunks(f, size=8192):
chunk = f.read(size)
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from datetime import date
from functools import wraps
from os.path import join
-from os import listdir, stat
+from os import listdir
from shutil import move, rmtree
from django.conf import settings
import re
import filecmp
-from django.db.models import Count
-
def active_tab(tab):
"""
@property
def was_merged(self):
- "Check if we have gallery size recorded"
+ """Check if we have gallery size recorded"""
return self.dest_size is not None
def merge(self):
for f in files:
p = self.get_prefix(f)
if p:
- if p > last_pfx: last_pfx = p
+ if p > last_pfx:
+ last_pfx = p
else:
files_prefixed = False
break
for f in files_other:
pfx = self.get_prefix(f)
if pfx is not None:
- if not pfx in prefixes:
+ if pfx not in prefixes:
last_pfx += 1
prefixes[pfx] = last_pfx
renamed_files_other[f] = self.set_prefix(f, prefixes[pfx])
# finally, move / rename files.
for frm, to in renamed_files.items():
move(join(self.path(self.dest), frm),
- join(self.path(self.dest), to))
+ join(self.path(self.dest), to))
for frm, to in renamed_files_other.items():
move(join(self.path(self.src), frm),
- join(self.path(self.dest), to))
+ join(self.path(self.dest), to))
rmtree(join(self.path(self.src)))
return self.dest
# Maybe subclass?
def sstdocument(text):
- #from catalogue.ebook_utils import RedakcjaDocProvider
from librarian.document import Document
return Document.from_string(
#: templates/catalogue/book_text.html:80
#, python-format
msgid "This resource has a <a href=\"%(url)s\">published version</a>."
-msgstr "Ten zasób posiada<a href=\"%(url)s\">opublikowaną wersję</a>."
+msgstr "Ten zasób posiada <a href=\"%(url)s\">opublikowaną wersję</a>."
#: templates/catalogue/book_text.html:83
msgid "This resource hasn't been published yet."
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from collections import defaultdict
-from django.db import transaction
-from lxml import etree
-
-
-class XmlUpdater(object):
- """A base class for massive XML updates.
-
- In a subclass, override `fix_tree` and/or use `fixes_field` decorator.
- Attributes:
- * commit_desc: commits description
- * retain_publishable: set publishable if head is (default: True)
- * only_first_chunk: process only first chunks of books (default: False)
- """
- commit_desc = "auto-update"
- retain_publishable = True
- only_first_chunk = False
-
- _element_fixers = defaultdict(list)
-
- def __init__(self):
- self.counters = defaultdict(lambda: 0)
-
- @classmethod
- def fixes_elements(cls, xpath):
- """Decorator, registering a function as a fixer for given field type.
-
- Any decorated function will be called like
- f(element, change=..., verbose=...)
- providing changeset as context.
-
- :param xpath: element lookup, e.g. ".//{namespace-uri}tag-name"
- :returns: True if anything changed
- """
- def wrapper(fixer):
- cls._element_fixers[xpath].append(fixer)
- return fixer
- return wrapper
-
- def fix_tree(self, tree, verbose):
- """Override to provide general tree-fixing mechanism.
-
- :param tree: the parsed XML tree
- :param verbose: verbosity level
- :returns: True if anythig changed
- """
- return False
-
- def fix_chunk(self, chunk, user, verbose=0, dry_run=False):
- """Runs the update for a single chunk."""
- if verbose >= 2:
- print chunk.get_absolute_url()
- old_head = chunk.head
- src = old_head.materialize()
- try:
- tree = etree.fromstring(src)
- except:
- if verbose:
- print "%s: invalid XML" % chunk.get_absolute_url()
- self.counters['Bad XML'] += 1
- return
-
- dirty = False
- # Call the general fixing function.
- if self.fix_tree(tree, verbose=verbose):
- dirty = True
- # Call the registered fixers.
- for xpath, fixers in self._element_fixers.items():
- for elem in tree.findall(xpath):
- for fixer in fixers:
- if fixer(elem, change=old_head, verbose=verbose):
- dirty = True
-
- if not dirty:
- self.counters['Clean'] += 1
- return
-
- if not dry_run:
- new_head = chunk.commit(
- etree.tostring(tree, encoding=unicode),
- author=user,
- description=self.commit_desc
- )
- if self.retain_publishable:
- if old_head.publishable:
- new_head.set_publishable(True)
- if verbose >= 2:
- print "done"
- self.counters['Updated chunks'] += 1
-
- def run(self, user, verbose=0, dry_run=False, books=None):
- """Runs the actual update."""
- if books is None:
- from catalogue.models import Book
- books = Book.objects.all()
-
- # Start transaction management.
- transaction.commit_unless_managed()
- transaction.enter_transaction_management()
- transaction.managed(True)
-
- for book in books:
- self.counters['All books'] += 1
- chunks = book.chunk_set.all()
- if self.only_first_chunk:
- chunks = chunks[:1]
- for chunk in chunks:
- self.counters['All chunks'] += 1
- self.fix_chunk(chunk, user, verbose, dry_run)
-
- transaction.commit()
- transaction.leave_transaction_management()
-
- def print_results(self):
- """Prints the counters."""
- for item in sorted(self.counters.items()):
- print "%s: %d" % item
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import sys
-from optparse import make_option
-from django.contrib.auth.models import User
-from django.core.management.base import BaseCommand
-from catalogue.models import Book
-
-
-class XmlUpdaterCommand(BaseCommand):
- """Base class for creating massive XML-updating commands.
-
- In a subclass, provide an XmlUpdater class in the `updater' attribute.
- """
- option_list = BaseCommand.option_list + (
- make_option('-q', '--quiet', action='store_false', dest='verbose',
- default=True, help='Less output'),
- make_option('-d', '--dry-run', action='store_true', dest='dry_run',
- default=False, help="Don't actually touch anything"),
- make_option('-u', '--username', dest='username', metavar='USER',
- help='Assign commits to this user (required, preferably yourself).'),
- )
- args = "[slug]..."
-
- def handle(self, *args, **options):
- verbose = options.get('verbose')
- dry_run = options.get('dry_run')
- username = options.get('username')
-
- if username:
- user = User.objects.get(username=username)
- else:
- print 'Please provide a username.'
- sys.exit(1)
-
- books = Book.objects.filter(slug__in=args) if args else None
-
- updater = self.updater()
- updater.run(user, verbose=verbose, dry_run=dry_run, books=books)
- updater.print_results()
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from librarian import RDFNS, WLURI, ValidationError
-from librarian.dcparser import BookInfo
-from catalogue.management import XmlUpdater
-from catalogue.management.commands import XmlUpdaterCommand
-
-
-class FixDC(XmlUpdater):
- commit_desc = "auto-fixing DC"
- retain_publishable = True
- only_first_chunk = True
-
- def fix_wluri(elem, change, verbose):
- try:
- WLURI.strict(elem.text)
- except ValidationError:
- correct_field = unicode(WLURI.from_slug(
- WLURI(elem.text.strip()).slug))
- try:
- WLURI.strict(correct_field)
- except ValidationError:
- # Can't make a valid WLURI out of it, leave as is.
- return False
- if verbose:
- print "Changing %s from %s to %s" % (
- elem.tag, elem.text, correct_field
- )
- elem.text = correct_field
- return True
- for field in BookInfo.FIELDS:
- if field.validator == WLURI:
- XmlUpdater.fixes_elements('.//' + field.uri)(fix_wluri)
-
- @XmlUpdater.fixes_elements(".//" + RDFNS("Description"))
- def fix_rdfabout(elem, change, verbose):
- correct_about = change.tree.book.correct_about()
- attr_name = RDFNS("about")
- current_about = elem.get(attr_name)
- if current_about != correct_about:
- if verbose:
- print "Changing rdf:about from %s to %s" % (
- current_about, correct_about
- )
- elem.set(attr_name, correct_about)
- return True
-
-
-class Command(XmlUpdaterCommand):
- updater = FixDC
- help = 'Fixes obvious errors in DC: rdf:about and WLURI format.'
+++ /dev/null
-# -*- coding: utf-8 -*-
-
-from collections import defaultdict
-import json
-from optparse import make_option
-import urllib2
-
-from django.core.management.base import BaseCommand
-from django.core.management.color import color_style
-from django.db import transaction
-from librarian.dcparser import BookInfo
-from librarian import ParseError, ValidationError
-
-from catalogue.models import Book
-
-
-WL_API = 'http://www.wolnelektury.pl/api/books/'
-
-
-class Command(BaseCommand):
- option_list = BaseCommand.option_list + (
- make_option('-q', '--quiet', action='store_false', dest='verbose', default=True,
- help='Less output'),
- )
- help = 'Imports XML files from WL.'
-
- def handle(self, *args, **options):
-
- self.style = color_style()
-
- verbose = options.get('verbose')
-
- # Start transaction management.
- transaction.commit_unless_managed()
- transaction.enter_transaction_management()
- transaction.managed(True)
-
- if verbose:
- print 'Reading currently managed files (skipping hidden ones).'
- slugs = defaultdict(list)
- for b in Book.objects.exclude(slug__startswith='.').all():
- if verbose:
- print b.slug
- text = b.materialize().encode('utf-8')
- try:
- info = BookInfo.from_string(text)
- except (ParseError, ValidationError):
- pass
- else:
- slugs[info.slug].append(b)
-
- book_count = 0
- commit_args = {
- "author_name": 'Platforma',
- "description": 'Automatycznie zaimportowane z Wolnych Lektur',
- "publishable": True,
- }
-
- if verbose:
- print 'Opening books list'
- for book in json.load(urllib2.urlopen(WL_API)):
- book_detail = json.load(urllib2.urlopen(book['href']))
- xml_text = urllib2.urlopen(book_detail['xml']).read()
- info = BookInfo.from_string(xml_text)
- previous_books = slugs.get(info.slug)
- if previous_books:
- if len(previous_books) > 1:
- print self.style.ERROR("There is more than one book "
- "with slug %s:"),
- previous_book = previous_books[0]
- comm = previous_book.slug
- else:
- previous_book = None
- comm = '*'
- print book_count, info.slug , '-->', comm
- Book.import_xml_text(xml_text, title=info.title[:255],
- slug=info.slug[:128], previous_book=previous_book,
- commit_args=commit_args)
- book_count += 1
-
- # Print results
- print
- print "Results:"
- print "Imported %d books from WL:" % (
- book_count, )
- print
-
-
- transaction.commit()
- transaction.leave_transaction_management()
-
from catalogue.models.plan import Plan
from catalogue.models.publish_log import PublishRecord
from catalogue.models.tag import Category, Tag
-# from catalogue.models.book import Book
-# from catalogue.models.listeners import *
from django.contrib.auth.models import User as AuthUser
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.contrib.auth.models import User
-from django.contrib.sites.models import Site
-from django.db import models, transaction
-from django.template.loader import render_to_string
-from django.utils.translation import ugettext_lazy as _
-from django.conf import settings
-from slughifi import slughifi
-
-import apiclient
-from catalogue.helpers import cached_in_field, GalleryMerger
-from catalogue.models import BookPublishRecord, ChunkPublishRecord, Project
-from catalogue.signals import post_publish
-from catalogue.tasks import refresh_instance, book_content_updated
-from catalogue.xml_tools import compile_text, split_xml
-from cover.models import Image
-from organizations.models import Organization
-import os
-import shutil
-import re
-
-
-class Book(models.Model):
- """ A document edited on the wiki """
-
- title = models.CharField(_('title'), max_length=255, db_index=True)
- slug = models.SlugField(_('slug'), max_length=128, unique=True, db_index=True)
- public = models.BooleanField(_('public'), default=True, db_index=True)
- gallery = models.CharField(u'materiały', max_length=255, blank=True)
- project = models.ForeignKey(Project, null=True, blank=True)
-
- owner_user = models.ForeignKey(User, null=True)
- owner_organization = models.ForeignKey(Organization, null=True)
-
- #wl_slug = models.CharField(_('title'), max_length=255, null=True, db_index=True, editable=False)
- parent = models.ForeignKey('self', null=True, blank=True, verbose_name=_('parent'), related_name="children", editable=False)
- parent_number = models.IntegerField(_('parent number'), null=True, blank=True, db_index=True, editable=False)
-
- # Cache
- _short_html = models.TextField(null=True, blank=True, editable=False)
- _single = models.NullBooleanField(editable=False, db_index=True)
- _new_publishable = models.NullBooleanField(editable=False)
- _published = models.NullBooleanField(editable=False)
- _on_track = models.IntegerField(null=True, blank=True, db_index=True, editable=False)
- dc_cover_image = models.ForeignKey(Image, blank=True, null=True,
- db_index=True, on_delete=models.SET_NULL, editable=False)
- dc_slug = models.CharField(max_length=128, null=True, blank=True,
- editable=False, db_index=True)
-
- class NoTextError(BaseException):
- pass
-
- class Meta:
- app_label = 'catalogue'
- ordering = ['title', 'slug']
- verbose_name = u'moduł'
- verbose_name_plural = u'moduły'
-
-
- # Representing
- # ============
-
- def __iter__(self):
- return iter(self.chunk_set.all())
-
- def __getitem__(self, chunk):
- return self.chunk_set.all()[chunk]
-
- def __len__(self):
- return self.chunk_set.count()
-
- def __nonzero__(self):
- """
- Necessary so that __len__ isn't used for bool evaluation.
- """
- return True
-
- def __unicode__(self):
- return self.title
-
- @models.permalink
- def get_absolute_url(self):
- return ("catalogue_book", [self.slug])
-
- def correct_about(self):
- return "http://%s%s" % (
- Site.objects.get_current().domain,
- self.get_absolute_url()
- )
-
- # Creating & manipulating
- # =======================
-
- def accessible(self, request):
- return self.public or request.user.is_authenticated()
-
- @classmethod
- @transaction.commit_on_success
- def create(cls, creator, text, *args, **kwargs):
- b = cls.objects.create(*args, **kwargs)
- b.chunk_set.all().update(creator=creator)
- b[0].commit(text, author=creator)
- return b
-
- def add(self, *args, **kwargs):
- """Add a new chunk at the end."""
- return self.chunk_set.reverse()[0].split(*args, **kwargs)
-
- @classmethod
- @transaction.commit_on_success
- def import_xml_text(cls, text=u'', previous_book=None,
- commit_args=None, **kwargs):
- """Imports a book from XML, splitting it into chunks as necessary."""
- texts = split_xml(text)
- if previous_book:
- instance = previous_book
- else:
- instance = cls(**kwargs)
- instance.save()
-
- # if there are more parts, set the rest to empty strings
- book_len = len(instance)
- for i in range(book_len - len(texts)):
- texts.append((u'pusta część %d' % (i + 1), u''))
-
- i = 0
- for i, (title, text) in enumerate(texts):
- if not title:
- title = u'część %d' % (i + 1)
-
- slug = slughifi(title)
-
- if i < book_len:
- chunk = instance[i]
- chunk.slug = slug[:50]
- chunk.title = title[:255]
- chunk.save()
- else:
- chunk = instance.add(slug, title)
-
- chunk.commit(text, **commit_args)
-
- return instance
-
- def make_chunk_slug(self, proposed):
- """
- Finds a chunk slug not yet used in the book.
- """
- slugs = set(c.slug for c in self)
- i = 1
- new_slug = proposed[:50]
- while new_slug in slugs:
- new_slug = "%s_%d" % (proposed[:45], i)
- i += 1
- return new_slug
-
- @transaction.commit_on_success
- def append(self, other, slugs=None, titles=None):
- """Add all chunks of another book to self."""
- assert self != other
-
- number = self[len(self) - 1].number + 1
- len_other = len(other)
- single = len_other == 1
-
- if slugs is not None:
- assert len(slugs) == len_other
- if titles is not None:
- assert len(titles) == len_other
- if slugs is None:
- slugs = [slughifi(t) for t in titles]
-
- for i, chunk in enumerate(other):
- # move chunk to new book
- chunk.book = self
- chunk.number = number
-
- if titles is None:
- # try some title guessing
- if other.title.startswith(self.title):
- other_title_part = other.title[len(self.title):].lstrip(' /')
- else:
- other_title_part = other.title
-
- if single:
- # special treatment for appending one-parters:
- # just use the guessed title and original book slug
- chunk.title = other_title_part
- if other.slug.startswith(self.slug):
- chunk.slug = other.slug[len(self.slug):].lstrip('-_')
- else:
- chunk.slug = other.slug
- else:
- chunk.title = ("%s, %s" % (other_title_part, chunk.title))[:255]
- else:
- chunk.slug = slugs[i]
- chunk.title = titles[i]
-
- chunk.slug = self.make_chunk_slug(chunk.slug)
- chunk.save()
- number += 1
- assert not other.chunk_set.exists()
-
- gm = GalleryMerger(self.gallery, other.gallery)
- self.gallery = gm.merge()
-
- # and move the gallery starts
- if gm.was_merged:
- for chunk in self[len(self) - len_other:]:
- old_start = chunk.gallery_start or 1
- chunk.gallery_start = old_start + gm.dest_size - gm.num_deleted
- chunk.save()
-
- other.delete()
-
-
- @transaction.commit_on_success
- def prepend_history(self, other):
- """Prepend history from all the other book's chunks to own."""
- assert self != other
-
- for i in range(len(self), len(other)):
- title = u"pusta część %d" % i
- chunk = self.add(slughifi(title), title)
- chunk.commit('')
-
- for i in range(len(other)):
- self[i].prepend_history(other[0])
-
- assert not other.chunk_set.exists()
- other.delete()
-
- def split(self):
- """Splits all the chunks into separate books."""
- self.title
- for chunk in self:
- book = Book.objects.create(title=chunk.title, slug=chunk.slug,
- public=self.public, gallery=self.gallery)
- book[0].delete()
- chunk.book = book
- chunk.number = 1
- chunk.save()
- assert not self.chunk_set.exists()
- self.delete()
-
- # State & cache
- # =============
-
- def last_published(self):
- try:
- return self.publish_log.all()[0].timestamp
- except IndexError:
- return None
-
- def assert_publishable(self):
- assert self.chunk_set.exists(), _('No chunks in the book.')
- try:
- changes = self.get_current_changes(publishable=True)
- except self.NoTextError:
- raise AssertionError(_('Not all chunks have publishable revisions.'))
-
- from librarian import NoDublinCore, ParseError, ValidationError
-
- try:
- bi = self.wldocument(changes=changes, strict=True).book_info
- except ParseError, e:
- raise AssertionError(_('Invalid XML') + ': ' + unicode(e))
- except NoDublinCore:
- raise AssertionError(_('No Dublin Core found.'))
- except ValidationError, e:
- raise AssertionError(_('Invalid Dublin Core') + ': ' + unicode(e))
-
- valid_about = self.correct_about()
- assert bi.about == valid_about, _("rdf:about is not") + " " + valid_about
-
- def publishable_error(self):
- try:
- return self.assert_publishable()
- except AssertionError, e:
- return e
- else:
- return None
-
- def hidden(self):
- return self.slug.startswith('.')
-
- def is_new_publishable(self):
- """Checks if book is ready for publishing.
-
- Returns True if there is a publishable version newer than the one
- already published.
-
- """
- new_publishable = False
- if not self.chunk_set.exists():
- return False
- for chunk in self:
- change = chunk.publishable()
- if not change:
- return False
- if not new_publishable and not change.publish_log.exists():
- new_publishable = True
- return new_publishable
- new_publishable = cached_in_field('_new_publishable')(is_new_publishable)
-
- def is_published(self):
- return self.publish_log.exists()
- published = cached_in_field('_published')(is_published)
-
- def get_on_track(self):
- if self.published:
- return -1
- stages = [ch.stage.ordering if ch.stage is not None else 0
- for ch in self]
- if not len(stages):
- return 0
- return min(stages)
- on_track = cached_in_field('_on_track')(get_on_track)
-
- def is_single(self):
- return len(self) == 1
- single = cached_in_field('_single')(is_single)
-
- #@cached_in_field('_short_html')
- def short_html(self):
- return render_to_string('catalogue/book_list/book.html', {'book': self})
-
- def book_info(self, publishable=True):
- try:
- book_xml = self.materialize(publishable=publishable)
- except self.NoTextError:
- pass
- else:
- from librarian.dcparser import BookInfo
- from librarian import NoDublinCore, ParseError, ValidationError
- try:
- return BookInfo.from_string(book_xml.encode('utf-8'))
- except (self.NoTextError, ParseError, NoDublinCore, ValidationError):
- return None
-
- def refresh_dc_cache(self):
- update = {
- 'dc_slug': None,
- 'dc_cover_image': None,
- }
-
- info = self.book_info()
- if info is not None:
- update['dc_slug'] = info.url.slug
- if info.cover_source:
- try:
- image = Image.objects.get(pk=int(info.cover_source.rstrip('/').rsplit('/', 1)[-1]))
- except:
- pass
- else:
- if info.cover_source == image.get_full_url():
- update['dc_cover_image'] = image
- Book.objects.filter(pk=self.pk).update(**update)
-
- def touch(self):
- # this should only really be done when text or publishable status changes
- book_content_updated.delay(self)
-
- update = {
- "_new_publishable": self.is_new_publishable(),
- "_published": self.is_published(),
- "_single": self.is_single(),
- "_on_track": self.get_on_track(),
- "_short_html": None,
- }
- Book.objects.filter(pk=self.pk).update(**update)
- refresh_instance(self)
-
- def refresh(self):
- """This should be done offline."""
- self.short_html
- self.single
- self.new_publishable
- self.published
-
- # Materializing & publishing
- # ==========================
-
- def get_current_changes(self, publishable=True):
- """
- Returns a list containing one Change for every Chunk in the Book.
- Takes the most recent revision (publishable, if set).
- Throws an error, if a proper revision is unavailable for a Chunk.
- """
- if publishable:
- changes = [chunk.publishable() for chunk in self]
- else:
- changes = [chunk.head for chunk in self if chunk.head is not None]
- if None in changes:
- raise self.NoTextError('Some chunks have no available text.')
- return changes
-
- def materialize(self, publishable=False, changes=None):
- """
- Get full text of the document compiled from chunks.
- Takes the current versions of all texts
- or versions most recently tagged for publishing,
- or a specified iterable changes.
- """
- if changes is None:
- changes = self.get_current_changes(publishable)
- return compile_text(change.materialize() for change in changes)
-
- def wldocument(self, publishable=True, changes=None,
- parse_dublincore=True, strict=False):
- from catalogue.ebook_utils import RedakcjaDocProvider
- from librarian.parser import WLDocument
-
- return WLDocument.from_string(
- self.materialize(publishable=publishable, changes=changes),
- provider=RedakcjaDocProvider(publishable=publishable),
- parse_dublincore=parse_dublincore,
- strict=strict)
-
- def publish(self, user):
- """
- Publishes a book on behalf of a (local) user.
- """
- self.assert_publishable()
- changes = self.get_current_changes(publishable=True)
- book_xml = self.materialize(changes=changes)
- apiclient.api_call(user, "books/", {"book_xml": book_xml})
- # record the publish
- br = BookPublishRecord.objects.create(book=self, user=user)
- for c in changes:
- ChunkPublishRecord.objects.create(book_record=br, change=c)
- post_publish.send(sender=br)
from datetime import date
from django.conf import settings
+from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db import models
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _
if header is None:
header = etree.fromstring(data).find('.//{http://nowoczesnapolska.org.pl/sst#}header')
metadata['title'] = getattr(header, 'text', ' ') or ' '
- #print 'meta', d['title']
+ # print 'meta', d['title']
m = t.find('metadata')
if m is None:
def get_plan(self):
try:
plan = self.plan_set.get(stage=self.stage)
- except:
+ except (ObjectDoesNotExist, MultipleObjectsReturned):
return None
return plan
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.contrib.auth.models import User
-from django.db import models
-from catalogue.models import Book, Chunk
-from catalogue.signals import post_publish
-
-
-def book_changed(sender, instance, created, **kwargs):
- instance.touch()
- for c in instance:
- c.touch()
-models.signals.post_save.connect(book_changed, sender=Book)
-
-
-def chunk_changed(sender, instance, created, **kwargs):
- instance.book.touch()
- instance.touch()
-models.signals.post_save.connect(chunk_changed, sender=Chunk)
-
-
-def user_changed(sender, instance, *args, **kwargs):
- books = set()
- for c in instance.chunk_set.all():
- books.add(c.book)
- c.touch()
- for b in books:
- b.touch()
-models.signals.post_save.connect(user_changed, sender=User)
-
-
-def publish_listener(sender, *args, **kwargs):
- sender.book.touch()
- for c in sender.book:
- c.touch()
-post_publish.connect(publish_listener)
-
-
-def listener_create(sender, instance, created, **kwargs):
- if created:
- instance.chunk_set.create(number=1, slug='1')
-models.signals.post_save.connect(listener_create, sender=Book)
-
from django.db import models
from catalogue.models import Document
+
class Plan(models.Model):
document = models.ForeignKey(Document)
stage = models.CharField(max_length=128)
class PublishRecord(models.Model):
"""A record left after publishing a Document."""
- document = models.ForeignKey('Document', verbose_name=_('document'), related_name='publish_log')
+ document = models.ForeignKey('catalogue.Document', verbose_name=_('document'), related_name='publish_log')
revision = models.ForeignKey(Revision, verbose_name=_('revision'), related_name='publish_log')
timestamp = models.DateTimeField(_('time'), auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('user'))
class Meta:
ordering = ['-timestamp']
verbose_name = _('book publish record')
- verbose_name = _('book publish records')
+ verbose_name_plural = _('book publish records')
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.db import models
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.dispatch import Signal
post_publish = Signal()
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from celery.task import task
from django.utils import translation
finally:
translation.activate(prev_language)
+
def refresh_instance(instance):
_refresh_by_pk.delay(type(instance), instance.pk, translation.get_language())
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-{% load wall %}
-
-
-{% block content %}
-
-<h1><a href='{% url "catalogue_activity" prev_day.isoformat %}'><</a>
- {% trans "Activity" %}: {{ day }}
- {% if next_day %}
- <a href='{% url "catalogue_activity" next_day.isoformat %}'>></a>
- {% endif %}
-</h1>
-
- {% day_wall day %}
-{% endblock content %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-
-{% block leftcolumn %}
- <form enctype="multipart/form-data" method="POST" action="">
- {% csrf_token %}
- {{ form.as_p }}
-
- <p><button type="submit">{% trans "Append book" %}</button></p>
- </form>
-{% endblock leftcolumn %}
-
-{% block rightcolumn %}
-{% endblock rightcolumn %}
{% endif %}
-{% comment %}
-
-
-{% if editable %}<form method='POST'>{% csrf_token %}{% endif %}
-<table class='editable'><tbody>
- {{ form.as_table }}
- {% if editable %}
- <tr><td></td><td><button type="submit">{% trans "Save" %}</button></td></tr>
- {% endif %}
-</tbody></table>
-{% if editable %}</form>{% endif %}
-
-{% if editable %}
- {% if book.gallery %}
- <p><a href="{% url 'catalogue_book_gallery' book.slug %}">{% trans "Edit gallery" %}</a></p>
- {% endif %}
-
- <p><a href="{% url 'catalogue_book_append' book.slug %}">{% trans "Append to other book" %}</a></p>
-{% endif %}
-
-
-<div class='section'>
-
- <h2>{% trans "Edit" %}</h2>
-
- <table class='single-book-list'><tbody>
- {% for chunk in book %}
- {{ chunk.short_html|safe }}
- {% endfor %}
- </tbody></table>
-
-</div>
-
-
-<div class='section'>
-
-
-<h2>{% trans "Publication" %}</h2>
-
-<div class="cover-preview">
-<img class="cover-preview" src="{% url 'cover_preview' book.slug %}" />
-{% if book.dc_cover_image %}
- <a href="{{ book.dc_cover_image.get_absolute_url }}">{{ book.dc_cover_image }}</a>
-{% endif %}
-</div>
-
-<p>{% trans "Last published" %}:
- {% if book.last_published %}
- {{ book.last_published }}
- {% else %}
- —
- {% endif %}
-</p>
-
-{% if publishable %}
- <p>
- <a href="{% url 'catalogue_book_xml' book.slug %}" rel="nofollow">{% trans "Full XML" %}</a><br/>
- <a target="_blank" href="{% url 'catalogue_book_html' book.slug %}" rel="nofollow">{% trans "HTML version" %}</a><br/>
- <a href="{% url 'catalogue_book_txt' book.slug %}" rel="nofollow">{% trans "TXT version" %}</a><br/>
- <a href="{% url 'catalogue_book_pdf' book.slug %}" rel="nofollow">{% trans "PDF version" %}</a><br/>
- <a href="{% url 'catalogue_book_epub' book.slug %}" rel="nofollow">{% trans "EPUB version" %}</a><br/>
- </p>
-
- {% if user.is_authenticated %}
- <!--
- Angel photos:
- Angels in Ely Cathedral (http://www.flickr.com/photos/21804434@N02/4483220595/) /
- mira66 (http://www.flickr.com/photos/21804434@N02/) /
- CC BY 2.0 (http://creativecommons.org/licenses/by/2.0/)
- -->
- <form method="POST" action="{% url 'catalogue_publish' book.slug %}">{% csrf_token %}
- <img src="{{ STATIC_URL }}img/angel-left.png" style="vertical-align: middle" />
- <button id="publish-button" type="submit">
- <span>{% trans "Publish" %}</span></button>
- <img src="{{ STATIC_URL }}img/angel-right.png" style="vertical-align: middle" />
- </form>
- {% else %}
- <a href="{% url 'login' %}">{% trans "Log in to publish." %}</a>
- {% endif %}
-{% else %}
- <p>{% trans "This book can't be published yet, because:" %}</p>
- <ul><li>{{ publishable_error }}</li></ul>
-{% endif %}
-
-<div style="clear: both;"></div>
-</div>
-
-
-{% endcomment %}
-
{% endblock %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-
-{% block leftcolumn %}
- <form enctype="multipart/form-data" method="POST" action="">
- {% csrf_token %}
- {{ form.as_p }}
-
- <p><button type="submit">{% trans "Save" %}</button></p>
- </form>
-{% endblock leftcolumn %}
-
-{% block rightcolumn %}
-{% endblock rightcolumn %}
+++ /dev/null
-{% load i18n %}
-
-<tr>
- <td><input type="checkbox" name="select_chunk" value="{{chunk.id}}" data-book-id="{{chunk.book.id}}" /></td>
- <td class='book-settings-column'></td>
- <td><a href="{% url 'catalogue_chunk_edit' chunk.book.slug chunk.slug %}" title='{% trans "Chunk settings" %}'>[c]</a></td>
- <td><a target="_blank" href="{{ chunk.get_absolute_url }}">
- <span class='chunkno'>{{ chunk.number }}.</span>
- {{ chunk.title }}</a></td>
- <td>{% if chunk.stage %}
- {{ chunk.stage }}
- {% else %}
- –
- {% endif %}</td>
- <td class='user-column'>{% if chunk.user %}
- <a href="{% url 'catalogue_user' chunk.user.username %}">
- {{ chunk.user.first_name }} {{ chunk.user.last_name }}
- </a>{% else %}
-
- {% endif %}</td>
-</td>
-<td>
- {% if chunk.new_publishable %}p{% endif %}
- {% if chunk.changed %}+{% endif %}
-</td>
-</tr>
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-
-{% block content %}
- <h1>{% trans "Split chunk" %}</h1>
-
- <form enctype="multipart/form-data" method="POST">
- {% csrf_token %}
- <table class='editable'>
- <tr><th>{% trans "Insert empty chunk after" %}:</th>
- <td><a href="{{ chunk.get_absolute_url }}">{{ chunk.pretty_name }}</a></td></tr>
- {{ form.as_table }}
- <tr><td></td><td><button type="submit">{% trans "Add chunk" %}</button></td></tr>
- </table>
- </form>
-{% endblock content %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-
-{% block content %}
- <h1>{% trans "Chunk settings" %}</h1>
-
- <form enctype="multipart/form-data" method="POST" action="{% if go_next %}?next={{ go_next }}{% endif %}">
- {% csrf_token %}
- <table class='editable'>
- <tr><th>{% trans "Book" %}:</th><td>{{ chunk.book }} ({{ chunk.number }}/{{ chunk.book|length }})</td></tr>
- {{ form.as_table}}
- <tr><td></td><td><button type="submit">{% trans "Save" %}</button></td></tr>
- </table>
-
- </form>
-
-
- <p><a href="{% url "catalogue_chunk_add" chunk.book.slug chunk.slug %}">{% trans "Split chunk" %}</a></p>
-
-{% endblock content %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-
-
-{% block leftcolumn %}
-
-
-<h2>{% trans "Bulk documents upload" %}</h2>
-
-<p>
-{% trans "Please submit a ZIP with UTF-8 encoded XML files. Files not ending with <code>.xml</code> will be ignored." %}
-</p>
-
-<form enctype="multipart/form-data" method="POST" action="">
-{% csrf_token %}
-{{ form.as_p }}
-<p><button type="submit">{% trans "Upload" %}</button></p>
-</form>
-
-<hr/>
-
-{% if error_list %}
-
- <p class='error'>{% trans "There have been some errors. No files have been added to the repository." %}
- <h3>{% trans "Offending files" %}</h3>
- <ul id='error-list'>
- {% for filename, title, error in error_list %}
- <li>{{ title }} (<code>{{ filename }}</code>): {{ error }}</li>
- {% endfor %}
- </ul>
-
- {% if ok_list %}
- <h3>{% trans "Correct files" %}</h3>
- <ul>
- {% for filename, slug, title in ok_list %}
- <li>{{ title }} (<code>{{ filename }}</code>)</li>
- {% endfor %}
- </ul>
- {% endif %}
-
-{% else %}
-
- {% if ok_list %}
- <p class='success'>{% trans "Files have been successfully uploaded to the repository." %}</p>
- <h3>{% trans "Uploaded files" %}</h3>
- <ul id='ok-list'>
- {% for filename, slug, title in ok_list %}
- <li><a href='{% url "wiki_editor" slug %}'>{{ title }}</a> (<code>{{ filename }})</a></li>
- {% endfor %}
- </ul>
- {% endif %}
-{% endif %}
-
-{% if skipped_list %}
- <h3>{% trans "Skipped files" %}</h3>
- <p>{% trans "Files skipped due to no <code>.xml</code> extension" %}</p>
- <ul id='skipped-list'>
- {% for filename in skipped_list %}
- <li>{{ filename }}</li>
- {% endfor %}
- </ul>
-{% endif %}
-
-
-{% endblock leftcolumn %}
-
-
-{% block rightcolumn %}
-{% endblock rightcolumn %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-
-{% load i18n %}
-
-{% block leftcolumn %}
-
-<h1>{% trans "Users" %}</h1>
-
-<ul>
-{% for user in users %}
- <li><a href="{% url 'catalogue_user' user.username %}">
- <span class="chunkno">{{ forloop.counter }}.</span>
- {{ user.first_name }} {{ user.last_name }}</a>
- ({{ user.count }})</li>
-{% endfor %}
-</ul>
-
-{% endblock leftcolumn %}
{% extends "catalogue/base.html" %}
-
-{% load i18n %}
-{% load catalogue book_list wall %}
-
-
-{% block leftcolumn %}
- <h1>{{ viewed_user|nice_name }}</h1>
- {% book_list viewed_user %}
-{% endblock leftcolumn %}
-
-{% block rightcolumn %}
- <h2>{% trans "Recent activity for" %} {{ viewed_user|nice_name }}</h2>
- {% wall viewed_user 10 %}
-{% endblock rightcolumn %}
+++ /dev/null
-{% load i18n %}
-{% load gravatar %}
-{% load email %}
-
-<ul class='wall'>
-{% for item in wall %}
- <li class="{{ item.tag }}{% if not item.user %} anonymous{% endif %}">
- <div class='gravatar'>
- {% if item.get_email %}
- {% gravatar_img_for_email item.get_email 32 %}
- <br/>
- {% endif %}
- </div>
-
- <div class="time">{{ item.timestamp }}</div>
- <h3>{{ item.header }}</h3>
- <a target="_blank" href='{{ item.url }}'>{{ item.title }}</a>
- <br/><strong>{% trans "user" %}:</strong>
- {% if item.user %}
- <a href="{% url 'catalogue_user' item.user.username %}">
- {{ item.user.first_name }} {{ item.user.last_name }}</a>
- <{{ item.user.email|email_link }}>
- {% else %}
- {{ item.user_name }}
- {% if item.email %}
- <{{ item.email|email_link }}>
- {% endif %}
- ({% trans "not logged in" %})
- {% endif %}
- <br/>{{ item.summary|linebreaksbr }}
- </li>
-{% empty %}
- <li>{% trans "No activity recorded." %}</li>
-{% endfor %}
-</ul>
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import absolute_import
-from django.core.urlresolvers import reverse
from django import template
-from django.utils.translation import ugettext as _
register = template.Library()
active = getattr(context['request'], 'catalogue_active_tab', None)
tabs = []
- user = context['user']
- #tabs.append(Tab('my', _('My page'), reverse("catalogue_user")))
-
- #tabs.append(Tab('activity', _('Activity'), reverse("catalogue_activity")))
- #tabs.append(Tab('all', _('All'), reverse("catalogue_document_list")))
- #tabs.append(Tab('users', _('Users'), reverse("catalogue_users")))
-
- #if user.has_perm('catalogue.add_book'):
- # tabs.append(Tab('create', _('Add'), reverse("catalogue_create_missing")))
+ # tabs.append(Tab('my', _('My page'), reverse("catalogue_user")))
+ #
+ # tabs.append(Tab('all', _('All'), reverse("catalogue_document_list")))
return {"tabs": tabs, "active_tab": active}
@register.filter
def nice_name(user):
return user.get_full_name() or user.username
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import template
from django.conf import settings
register = template.Library()
if uri.startswith('file://'):
uri = "https://milpeer.eu%suploads/%d/%s" % (settings.MEDIA_URL, document.pk, uri[len('file://'):])
return uri
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import template
register = template.Library()
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import absolute_import
-from re import split
-from django.db.models import Q, Count
+from django.db.models import Q
from django import template
from django.utils.translation import ugettext_lazy as _
-from django.contrib.auth.models import User
from catalogue.models import Document
register = template.Library()
-class ChunksList(object):
- def __init__(self, chunk_qs):
- #self.chunk_qs = chunk_qs#.annotate(
- #book_length=Count('book__chunk')).select_related(
- #'book')#, 'stage__name',
- #'user')
- self.chunk_qs = chunk_qs.select_related('book__hidden')
-
- self.book_qs = chunk_qs.values('book_id')
-
- def __getitem__(self, key):
- if isinstance(key, slice):
- return self.get_slice(key)
- elif isinstance(key, int):
- return self.get_slice(slice(key, key+1))[0]
- else:
- raise TypeError('Unsupported list index. Must be a slice or an int.')
-
- def __len__(self):
- return self.book_qs.count()
-
- def get_slice(self, slice_):
- book_ids = [x['book_id'] for x in self.book_qs[slice_]]
- chunk_qs = self.chunk_qs.filter(book__in=book_ids)
-
- chunks_list = []
- book = None
- for chunk in chunk_qs:
- if chunk.book != book:
- book = chunk.book
- chunks_list.append(ChoiceChunks(book, [chunk]))
- else:
- chunks_list[-1].chunks.append(chunk)
- return chunks_list
-
-
-class ChoiceChunks(object):
- """
- Associates the given chunks iterable for a book.
- """
-
- chunks = None
-
- def __init__(self, book, chunks):
- self.book = book
- self.chunks = chunks
-
-
-def foreign_filter(qs, value, filter_field, model, model_field='slug', unset='-'):
- #print qs, value, filter_field, model, model_field, unset
- if value == unset:
- return qs.filter(**{filter_field: None})
- if not value:
- return qs
- try:
- obj = model._default_manager.get(**{model_field: value})
- except model.DoesNotExist:
- return qs.none()
- else:
- return qs.filter(**{filter_field: obj})
-
-
-def search_filter(qs, value, filter_fields):
- if not value:
- return qs
- q = Q(**{"%s__icontains" % filter_fields[0]: value})
- for field in filter_fields[1:]:
- q |= Q(**{"%s__icontains" % field: value})
- return qs.filter(q)
-
-
_states = [
('publishable', _('publishable'), Q(book___new_publishable=True)),
('changed', _('changed'), Q(_changed=True)),
_states_dict = dict([(s[0], s[2]) for s in _states])
-def document_list_filter(request, **kwargs):
-
- def arg_or_GET(field):
- return kwargs.get(field, request.GET.get(field))
-
- if arg_or_GET('all'):
- chunks = Chunk.objects.all()
- else:
- chunks = Chunk.visible_objects.all()
-
- chunks = chunks.order_by('book__title', 'book', 'number')
-
- if not request.user.is_authenticated():
- chunks = chunks.filter(book__public=True)
-
- state = arg_or_GET('status')
- if state in _states_dict:
- chunks = chunks.filter(_states_dict[state])
-
- chunks = foreign_filter(chunks, arg_or_GET('user'), 'user', User, 'username')
- chunks = foreign_filter(chunks, arg_or_GET('stage'), 'stage', Chunk.tag_model, 'slug')
- chunks = search_filter(chunks, arg_or_GET('title'), ['book__title', 'title'])
- chunks = foreign_filter(chunks, arg_or_GET('project'), 'book__project', Project, 'pk')
- return chunks
-
-
@register.inclusion_tag('catalogue/book_list/book_list.html', takes_context=True)
def document_list(context, user=None, organization=None):
request = context['request']
- #~ if user:
- #~ filters = {"user": user}
- #~ new_context = {"viewed_user": user}
- #~ else:
- #~ filters = {}
- #~ new_context = {
- #~ "users": User.objects.annotate(
- #~ count=Count('chunk')).filter(count__gt=0).order_by(
- #~ '-count', 'last_name', 'first_name'),
- #~ "other_users": User.objects.annotate(
- #~ count=Count('chunk')).filter(count=0).order_by(
- #~ 'last_name', 'first_name'),
- #~ }
+ # if user:
+ # filters = {"user": user}
+ # new_context = {"viewed_user": user}
+ # else:
+ # filters = {}
+ # new_context = {
+ # "users": User.objects.annotate(
+ # count=Count('chunk')).filter(count__gt=0).order_by(
+ # '-count', 'last_name', 'first_name'),
+ # "other_users": User.objects.annotate(
+ # count=Count('chunk')).filter(count=0).order_by(
+ # 'last_name', 'first_name'),
+ # }
docs = Document.objects.filter(deleted=False)
if user is not None:
- docs = docs.filter(Q(owner_user=user) | Q(owner_organization__membership__user=user) | Q(assigned_to=user)).distinct()
+ docs = docs.filter(
+ Q(owner_user=user) | Q(owner_organization__membership__user=user) | Q(assigned_to=user)).distinct()
if organization is not None:
docs = docs.filter(owner_organization=organization)
new_context = {}
new_context.update({
- #"filters": True,
+ # "filters": True,
"request": request,
"books": docs,
- #"books": ChunksList(document_list_filter(request, **filters)),
- #"stages": Chunk.tag_model.objects.all(),
- #"states": _states_options,
- #"projects": Project.objects.all(),
+ # "stages": Chunk.tag_model.objects.all(),
+ # "states": _states_options,
})
return new_context
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.utils import translation
from django import template
def flat_lang(page):
try:
return type(page).objects.get(url="%s%s/" % (page.url, translation.get_language()))
- except:
+ except (ObjectDoesNotExist, MultipleObjectsReturned):
return page
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from re import split
from django import template
del(params[key])
else:
params[key] = template.Variable(value).resolve(context)
- return '?%s' % params.urlencode()
+ return '?%s' % params.urlencode()
@register.tag
+++ /dev/null
-from __future__ import absolute_import
-
-from datetime import timedelta
-from django.db.models import Q
-from django.core.urlresolvers import reverse
-from django.contrib.comments.models import Comment
-from django import template
-from django.utils.translation import ugettext as _
-
-from catalogue.models import Chunk, BookPublishRecord
-
-register = template.Library()
-
-
-class WallItem(object):
- title = ''
- summary = ''
- url = ''
- timestamp = ''
- user = None
- user_name = ''
- email = ''
-
- def __init__(self, tag):
- self.tag = tag
-
- def get_email(self):
- if self.user:
- return self.user.email
- else:
- return self.email
-
-
-def changes_wall(user=None, max_len=None, day=None):
- qs = Chunk.change_model.objects.order_by('-created_at')
- qs = qs.select_related('author', 'tree', 'tree__book__title')
- if user is not None:
- qs = qs.filter(Q(author=user) | Q(tree__user=user))
- if max_len is not None:
- qs = qs[:max_len]
- if day is not None:
- next_day = day + timedelta(1)
- qs = qs.filter(created_at__gte=day, created_at__lt=next_day)
- for item in qs:
- tag = 'stage' if item.tags.count() else 'change'
- chunk = item.tree
- w = WallItem(tag)
- if user and item.author != user:
- w.header = _('Related edit')
- else:
- w.header = _('Edit')
- w.title = chunk.pretty_name()
- w.summary = item.description
- w.url = reverse('wiki_editor',
- args=[chunk.book.slug, chunk.slug]) + '?diff=%d' % item.revision
- w.timestamp = item.created_at
- w.user = item.author
- w.user_name = item.author_name
- w.email = item.author_email
- yield w
-
-
-# TODO: marked for publishing
-
-
-def published_wall(user=None, max_len=None, day=None):
- qs = BookPublishRecord.objects.select_related('book__title')
- if user:
- # TODO: published my book
- qs = qs.filter(Q(user=user))
- if max_len is not None:
- qs = qs[:max_len]
- if day is not None:
- next_day = day + timedelta(1)
- qs = qs.filter(timestamp__gte=day, timestamp__lt=next_day)
- for item in qs:
- w = WallItem('publish')
- w.header = _('Publication')
- w.title = item.book.title
- w.timestamp = item.timestamp
- w.url = item.book.get_absolute_url()
- w.user = item.user
- w.email = item.user.email
- yield w
-
-
-def comments_wall(user=None, max_len=None, day=None):
- qs = Comment.objects.filter(is_public=True).select_related().order_by('-submit_date')
- if user:
- # TODO: comments concerning my books
- qs = qs.filter(Q(user=user))
- if max_len is not None:
- qs = qs[:max_len]
- if day is not None:
- next_day = day + timedelta(1)
- qs = qs.filter(submit_date__gte=day, submit_date__lt=next_day)
- for item in qs:
- w = WallItem('comment')
- w.header = _('Comment')
- w.title = item.content_object
- w.summary = item.comment
- w.url = item.content_object.get_absolute_url()
- w.timestamp = item.submit_date
- w.user = item.user
- ui = item.userinfo
- w.email = item.email
- w.user_name = item.name
- yield w
-
-
-def big_wall(walls, max_len=None):
- """
- Takes some WallItem iterators and zips them into one big wall.
- Input iterators must already be sorted by timestamp.
- """
- subwalls = []
- for w in walls:
- try:
- subwalls.append([next(w), w])
- except StopIteration:
- pass
-
- if max_len is None:
- max_len = -1
- while max_len and subwalls:
- i, next_item = max(enumerate(subwalls), key=lambda x: x[1][0].timestamp)
- yield next_item[0]
- max_len -= 1
- try:
- next_item[0] = next(next_item[1])
- except StopIteration:
- del subwalls[i]
-
-
-@register.inclusion_tag("catalogue/wall.html", takes_context=True)
-def wall(context, user=None, max_len=100):
- return {
- "request": context['request'],
- "STATIC_URL": context['STATIC_URL'],
- "wall": big_wall([
- changes_wall(user, max_len),
- published_wall(user, max_len),
- comments_wall(user, max_len),
- ], max_len)}
-
-@register.inclusion_tag("catalogue/wall.html", takes_context=True)
-def day_wall(context, day):
- return {
- "request": context['request'],
- "STATIC_URL": context['STATIC_URL'],
- "wall": big_wall([
- changes_wall(day=day),
- published_wall(day=day),
- comments_wall(day=day),
- ])}
# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
#
-from catalogue.tests.book import *
-from catalogue.tests.gallery import *
-from catalogue.tests.publish import *
-from catalogue.tests.xml_updater import *
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""Tests for manipulating books in the catalogue."""
-
-from django.test import TestCase
-from django.contrib.auth.models import User
-from catalogue.models import Book
-
-
-class ManipulationTests(TestCase):
-
- def setUp(self):
- self.user = User.objects.create(username='tester')
- self.book1 = Book.create(self.user, 'book 1', slug='book1')
- self.book2 = Book.create(self.user, 'book 2', slug='book2')
-
- def test_append(self):
- self.book1.append(self.book2)
- self.assertEqual(Book.objects.all().count(), 1)
- self.assertEqual(len(self.book1), 2)
-
- def test_append_to_self(self):
- with self.assertRaises(AssertionError):
- self.book1.append(Book.objects.get(pk=self.book1.pk))
- self.assertEqual(Book.objects.all().count(), 2)
- self.assertEqual(len(self.book1), 1)
-
- def test_prepend_history(self):
- self.book1.prepend_history(self.book2)
- self.assertEqual(Book.objects.all().count(), 1)
- self.assertEqual(len(self.book1), 1)
- self.assertEqual(self.book1.materialize(), 'book 1')
-
- def test_prepend_history_to_self(self):
- with self.assertRaises(AssertionError):
- self.book1.prepend_history(self.book1)
- self.assertEqual(Book.objects.all().count(), 2)
- self.assertEqual(self.book1.materialize(), 'book 1')
- self.assertEqual(self.book2.materialize(), 'book 2')
-
- def test_split_book(self):
- self.book1.chunk_set.create(number=2, title='Second chunk',
- slug='book3')
- self.book1[1].commit('I survived!')
- self.assertEqual(len(self.book1), 2)
- self.book1.split()
- self.assertEqual(set([b.slug for b in Book.objects.all()]),
- set(['book2', '1', 'book3']))
- self.assertEqual(
- Book.objects.get(slug='book3').materialize(),
- 'I survived!')
+++ /dev/null
-<utwor>
- <liryka_l>
-
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
-<rdf:Description rdf:about="http://example.com/documents/book/test-book/">
-<dc:creator xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Mickiewicz, Adam</dc:creator>
-<dc:title xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Do M***</dc:title>
-<dc:publisher xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Fundacja Nowoczesna Polska</dc:publisher>
-<dc:subject.period xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Romantyzm</dc:subject.period>
-<dc:subject.type xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Liryka</dc:subject.type>
-<dc:subject.genre xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Wiersz</dc:subject.genre>
-<!--dc:description xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description-->
-<dc:identifier.url xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">http://wolnelektury.pl/katalog/lektura/sonety-odeskie-do-m</dc:identifier.url>
-<dc:source.URL xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">http://www.polona.pl/Content/2222</dc:source.URL>
-<dc:source xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922</dc:source>
-
-<dc:rights xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Domena publiczna - Adam Mickiewicz zm. 1855</dc:rights>
-<dc:date.pd xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">1926</dc:date.pd>
-<dc:format xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">xml</dc:format>
-<dc:type xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">text</dc:type>
-<dc:type xml:lang="en" xmlns:dc="http://purl.org/dc/elements/1.1/">text</dc:type>
-<dc:date xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">2007-09-06</dc:date>
-<dc:language xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">pol</dc:language>
-
-</rdf:Description>
-</rdf:RDF>
-
-<autor_utworu>Adam Mickiewicz</autor_utworu>
-<dzielo_nadrzedne>Sonety odeskie</dzielo_nadrzedne>
-<nazwa_utworu>Do M***</nazwa_utworu>
-
-<nota><akap>Wiérsz napisany w roku 1822</akap></nota>
-
-
-<strofa>Precz z moich oczu!... posłucham od razu,/
-Precz z mego serca!... i serce posłucha,/
-Precz z méj pamięci!... Nie! tego rozkazu/
-Moja i twoja pamięć nie posłucha.</strofa>
-
-<!-- TRIM_END -->
-</liryka_l>
-</utwor>
+++ /dev/null
-<utwor><liryka_l>
-<!-- TRIM_BEGIN -->
-
-<strofa>Jak cień tém dłuższy, gdy padnie z daleka,/
-Tém szerzéj koło żałobne roztoczy,/
-Tak moja postać, im daléj ucieka,/
-Tém grubszym kirem twą pamięć pomroczy.</strofa>
-
-
-</liryka_l>
-</utwor>
+++ /dev/null
-<utwor>
- <liryka_l>
-
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
-<rdf:Description rdf:about="http://example.com/documents/book/test-book/">
-<dc:creator xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Mickiewicz, Adam</dc:creator>
-<dc:title xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Do M***</dc:title>
-<dc:publisher xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Fundacja Nowoczesna Polska</dc:publisher>
-<dc:subject.period xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Romantyzm</dc:subject.period>
-<dc:subject.type xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Liryka</dc:subject.type>
-<dc:subject.genre xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Wiersz</dc:subject.genre>
-<!--dc:description xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Publikacja zrealizowana w ramach projektu Wolne Lektury (http://wolnelektury.pl). Reprodukcja cyfrowa wykonana przez Bibliotekę Narodową z egzemplarza pochodzącego ze zbiorów BN.</dc:description-->
-<dc:identifier.url xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">http://wolnelektury.pl/katalog/lektura/sonety-odeskie-do-m</dc:identifier.url>
-<dc:source.URL xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">http://www.polona.pl/Content/2222</dc:source.URL>
-<dc:source xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Mickiewicz, Adam (1798-1855), Poezje, tom 1 (Wiersze młodzieńcze - Ballady i romanse - Wiersze do r. 1824), Krakowska Spółdzielnia Wydawnicza, wyd. 2 zwiększone, Kraków, 1922</dc:source>
-
-<dc:rights xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">Domena publiczna - Adam Mickiewicz zm. 1855</dc:rights>
-<dc:date.pd xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">1926</dc:date.pd>
-<dc:format xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">xml</dc:format>
-<dc:type xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">text</dc:type>
-<dc:type xml:lang="en" xmlns:dc="http://purl.org/dc/elements/1.1/">text</dc:type>
-<dc:date xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">2007-09-06</dc:date>
-<dc:language xml:lang="pl" xmlns:dc="http://purl.org/dc/elements/1.1/">pol</dc:language>
-
-</rdf:Description>
-</rdf:RDF>
-
-<autor_utworu>Adam Mickiewicz</autor_utworu>
-<dzielo_nadrzedne>Sonety odeskie</dzielo_nadrzedne>
-<nazwa_utworu>Do M***</nazwa_utworu>
-
-<nota><akap>Wiérsz napisany w roku 1822</akap></nota>
-
-
-<strofa>Precz z moich oczu!... posłucham od razu,/
-Precz z mego serca!... i serce posłucha,/
-Precz z méj pamięci!... Nie! tego rozkazu/
-Moja i twoja pamięć nie posłucha.</strofa>
-
-
-
-<strofa>Jak cień tém dłuższy, gdy padnie z daleka,/
-Tém szerzéj koło żałobne roztoczy,/
-Tak moja postać, im daléj ucieka,/
-Tém grubszym kirem twą pamięć pomroczy.</strofa>
-
-
-</liryka_l>
-</utwor>
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""Tests for galleries of scans."""
-
-from os.path import join, basename, exists
-from os import makedirs, listdir
-from django.test import TestCase
-from django.contrib.auth.models import User
-from catalogue.models import Book
-from tempfile import mkdtemp
-from django.conf import settings
-
-
-class GalleryAppendTests(TestCase):
- def setUp(self):
- self.user = User.objects.create(username='tester')
- self.book1 = Book.create(self.user, 'book 1', slug='book1')
- self.book1.chunk_set.create(number=2, title='Second chunk',
- slug='book 1 / 2')
- c=self.book1[1]
- c.gallery_start=3
-
- self.scandir = join(settings.MEDIA_ROOT, settings.IMAGE_DIR)
- if not exists(self.scandir):
- makedirs(self.scandir)
-
- def make_gallery(self, book, files):
- d = mkdtemp('gallery', dir=self.scandir)
- for named, cont in files.items():
- f = open(join(d, named), 'w')
- f.write(cont)
- f.close()
- book.gallery = basename(d)
-
-
- def test_both_indexed(self):
- self.book2 = Book.create(self.user, 'book 2', slug='book2')
- self.book2.chunk_set.create(number=2, title='Second chunk of second book',
- slug='book 2 / 2')
-
- c = self.book2[1]
- c.gallery_start = 3
- c.save()
-
- print "gallery starts:",self.book2[0].gallery_start, self.book2[1].gallery_start
-
- self.make_gallery(self.book1, {
- '1-0001_1l' : 'aa',
- '1-0001_2r' : 'bb',
- '1-0002_1l' : 'cc',
- '1-0002_2r' : 'dd',
- })
-
- self.make_gallery(self.book2, {
- '1-0001_1l' : 'dd', # the same, should not be moved
- '1-0001_2r' : 'ff',
- '2-0002_1l' : 'gg',
- '2-0002_2r' : 'hh',
- })
-
- self.book1.append(self.book2)
-
- files = listdir(join(self.scandir, self.book1.gallery))
- files.sort()
- print files
- self.assertEqual(files, [
- '1-0001_1l',
- '1-0001_2r',
- '1-0002_1l',
- '1-0002_2r',
- # '2-0001_1l',
- '2-0001_2r',
- '3-0002_1l',
- '3-0002_2r',
- ])
-
- self.assertEqual((4, 6), (self.book1[2].gallery_start, self.book1[3].gallery_start))
-
-
- def test_none_indexed(self):
- self.book2 = Book.create(self.user, 'book 2', slug='book2')
- self.make_gallery(self.book1, {
- '0001_1l' : 'aa',
- '0001_2r' : 'bb',
- '0002_1l' : 'cc',
- '0002_2r' : 'dd',
- })
-
- self.make_gallery(self.book2, {
- '0001_1l' : 'ee',
- '0001_2r' : 'ff',
- '0002_1l' : 'gg',
- '0002_2r' : 'hh',
- })
-
- self.book1.append(self.book2)
-
- files = listdir(join(self.scandir, self.book1.gallery))
- files.sort()
- print files
- self.assertEqual(files, [
- '0-0001_1l',
- '0-0001_2r',
- '0-0002_1l',
- '0-0002_2r',
- '1-0001_1l',
- '1-0001_2r',
- '1-0002_1l',
- '1-0002_2r',
- ])
-
-
- def test_none_indexed(self):
- import nose.tools
- self.book2 = Book.create(self.user, 'book 2', slug='book2')
- self.make_gallery(self.book1, {
- '1-0001_1l' : 'aa',
- '1-0001_2r' : 'bb',
- '1002_1l' : 'cc',
- '1002_2r' : 'dd',
- })
-
- self.make_gallery(self.book2, {
- '0001_1l' : 'ee',
- '0001_2r' : 'ff',
- '0002_1l' : 'gg',
- '0002_2r' : 'hh',
- })
-
- self.book1.append(self.book2)
-
- files = listdir(join(self.scandir, self.book1.gallery))
- files.sort()
- print files
- self.assertEqual(files, [
- '0-1-0001_1l',
- '0-1-0001_2r',
- '0-1002_1l',
- '0-1002_2r',
- '1-0001_1l',
- '1-0001_2r',
- '1-0002_1l',
- '1-0002_2r',
- ])
-
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""Tests for the publishing process."""
-
-from catalogue.test_utils import get_fixture
-
-from mock import patch
-from django.test import TestCase
-from django.contrib.auth.models import User
-from catalogue.models import Book
-
-
-class PublishTests(TestCase):
- def setUp(self):
- self.user = User.objects.create(username='tester')
- self.text1 = get_fixture('chunk1.xml')
- self.book = Book.create(self.user, self.text1, slug='test-book')
-
- @patch('apiclient.api_call')
- def test_unpublishable(self, api_call):
- with self.assertRaises(AssertionError):
- self.book.publish(self.user)
-
- @patch('apiclient.api_call')
- def test_publish(self, api_call):
- self.book[0].head.set_publishable(True)
- self.book.publish(self.user)
- api_call.assert_called_with(self.user, 'books/', {"book_xml": self.text1})
-
- @patch('apiclient.api_call')
- def test_publish_multiple(self, api_call):
- self.book[0].head.set_publishable(True)
- self.book[0].split(slug='part-2')
- self.book[1].commit(get_fixture('chunk2.xml'))
- self.book[1].head.set_publishable(True)
- self.book.publish(self.user)
- api_call.assert_called_with(self.user, 'books/', {"book_xml": get_fixture('expected.xml')})
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-"""XmlUpdater tests."""
-
-from catalogue.test_utils import get_fixture
-from django.test import TestCase
-from django.contrib.auth.models import User
-from catalogue.models import Book
-from catalogue.management import XmlUpdater
-from librarian import DCNS
-
-
-class XmlUpdaterTests(TestCase):
- class SimpleUpdater(XmlUpdater):
- @XmlUpdater.fixes_elements('.//' + DCNS('title'))
- def fix_title(element, **kwargs):
- element.text = element.text + " fixed"
- return True
-
- def setUp(self):
- self.user = User.objects.create(username='tester')
- text = get_fixture('chunk1.xml')
- Book.create(self.user, text, slug='test-book')
- self.title = "Do M***"
-
- def test_xml_updater(self):
- self.SimpleUpdater().run(self.user)
- self.assertEqual(
- Book.objects.get(slug='test-book').wldocument(
- publishable=False).book_info.title,
- self.title + " fixed"
- )
# -*- coding: utf-8
from django.conf.urls import patterns, url
-from django.contrib.auth.decorators import permission_required, login_required
-from catalogue.views import GalleryView, GalleryPackageView
+from django.contrib.auth.decorators import login_required
+from catalogue.views import GalleryView
urlpatterns = patterns(
url(r'^upcoming/$', 'upcoming', name='catalogue_upcoming'),
url(r'^finished/$', 'finished', name='catalogue_finished'),
- # url(r'^catalogue/$', 'document_list', name='catalogue_document_list'),
url(r'^user/$', 'my', name='catalogue_user'),
url(r'^user/(?P<username>[^/]+)/$', 'user', name='catalogue_user'),
- url(r'^users/$', 'users', name='catalogue_users'),
- url(r'^activity/$', 'activity', name='catalogue_activity'),
- url(r'^activity/(?P<isodate>\d{4}-\d{2}-\d{2})/$',
- 'activity', name='catalogue_activity'),
-
- # url(r'^upload/$', 'upload', name='catalogue_upload'),
url(r'^create/(?P<slug>[^/]*)/',
'create_missing', name='catalogue_create_missing'),
url(r'^doc/(?P<pk>\d+)/publish$', 'publish', name="catalogue_publish"),
url(r'^doc/(?P<pk>\d+)/unpublish$', 'unpublish', name="catalogue_unpublish"),
- # url(r'^(?P<name>[^/]+)/publish/(?P<version>\d+)$', 'publish', name="catalogue_publish"),
url(r'^(?P<pk>[^/]+)/schedule/$', 'book_schedule', name="catalogue_book_schedule"),
url(r'^(?P<pk>[^/]+)/owner/$', 'book_owner', name="catalogue_book_owner"),
url(r'^(?P<pk>[^/]+)/delete/$', 'book_delete', name="catalogue_book_delete"),
- # url(r'^book/(?P<slug>[^/]+)/$', 'book', name="catalogue_book"),
-
url(r'^(?P<pk>[^/]+)/attachments/$',
login_required()(GalleryView.as_view()),
name="catalogue_book_gallery"),
- # url(r'^attachments/$',
- # login_required()(GalleryView.as_view()),
- # name="catalogue_attachments"),
- # url(r'^attachments/(?P<pk>\d+)/$',
- # login_required()(GalleryView.as_view()),
- # name="catalogue_attachments"),
- url(r'^book/(?P<slug>[^/]+)/gallery/package$',
- permission_required('catalogue.change_book')(GalleryPackageView.as_view()),
- name="catalogue_book_gallery_package"),
- # url(r'^book/(?P<slug>[^/]+)/xml$', 'book_xml', name="catalogue_book_xml"),
- # url(r'^book/(?P<slug>[^/]+)/txt$', 'book_txt', name="catalogue_book_txt"),
url(r'^(?P<pk>\d+)/$', 'book_html', name="catalogue_html"),
url(r'^(?P<pk>\d+)/preview/$', 'book_html', {'preview': True}, name="catalogue_preview"),
url(r'^(?P<pk>\d+)/rev(?P<rev_pk>\d+)/preview/$', 'book_html', {'preview': True}, name="catalogue_preview_rev"),
url(r'^(?P<pk>\d+)/rev(?P<rev_pk>\d+)/pdf/$', 'book_pdf', name="catalogue_pdf"),
url(r'^(?P<pk>\d+)/rev(?P<rev_pk>\d+)/epub/$', 'book_epub', name="catalogue_epub"),
-
- # url(r'^book/(?P<slug>[^/]+)/epub$', 'book_epub', name="catalogue_book_epub"),
- # url(r'^book/(?P<slug>[^/]+)/pdf$', 'book_pdf', name="catalogue_book_pdf"),
-
- # url(r'^chunk_add/(?P<slug>[^/]+)/(?P<chunk>[^/]+)/$',
- # 'chunk_add', name="catalogue_chunk_add"),
- # url(r'^chunk_edit/(?P<slug>[^/]+)/(?P<chunk>[^/]+)/$',
- # 'chunk_edit', name="catalogue_chunk_edit"),
- # url(r'^book_append/(?P<slug>[^/]+)/$',
- # 'book_append', name="catalogue_book_append"),
- # url(r'^chunk_mass_edit',
- # 'chunk_mass_edit', name='catalogue_chunk_mass_edit'),
)
# -*- coding: utf-8 -*-
-from datetime import date, timedelta
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
import logging
import os
import shutil
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
-from django.db.models import Count
from django import http
from django.http import Http404
from django.shortcuts import get_object_or_404, render, redirect
from django.views.decorators.http import require_POST
from catalogue import forms
-from catalogue import helpers
from catalogue.helpers import active_tab
from librarian import BuildError
from .constants import STAGES
from .models import Document, Plan
from dvcs.models import Revision
from organizations.models import Organization
-from fileupload.views import UploadView, PackageView
+from fileupload.views import UploadView
#
# Quick hack around caching problems, TODO: use ETags
})
-@active_tab('users')
-def users(request):
- return render(request, 'catalogue/user_list.html', {
- 'users': User.objects.all().annotate(count=Count('chunk')).order_by(
- '-count', 'last_name', 'first_name'),
- })
-
-
-@active_tab('activity')
-def activity(request, isodate=None):
- today = date.today()
- try:
- day = helpers.parse_isodate(isodate)
- except ValueError:
- day = today
-
- if day > today:
- raise Http404
- if day != today:
- next_day = day + timedelta(1)
- prev_day = day - timedelta(1)
-
- return render(request, 'catalogue/activity.html', locals())
-
-
@never_cache
def logout_then_redirect(request):
auth.logout(request)
return http.HttpResponseRedirect(urlquote_plus(request.GET.get('next', '/'), safe='/?='))
-# @permission_required('catalogue.add_book')
@login_required
@active_tab('create')
def create_missing(request):
})
-# @permission_required('catalogue.add_book')
-# @active_tab('upload')
-# def upload(request):
-# if request.method == "POST":
-# form = forms.DocumentsUploadForm(request.POST, request.FILES)
-# if form.is_valid():
-# import slughifi
-#
-# if request.user.is_authenticated():
-# creator = request.user
-# else:
-# creator = None
-#
-# zip = form.cleaned_data['zip']
-# skipped_list = []
-# ok_list = []
-# error_list = []
-# slugs = {}
-# existing = [book.slug for book in Book.objects.all()]
-# for filename in zip.namelist():
-# if filename[-1] == '/':
-# continue
-# title = os.path.basename(filename)[:-4]
-# slug = slughifi(title)
-# if not (slug and filename.endswith('.xml')):
-# skipped_list.append(filename)
-# elif slug in slugs:
-# error_list.append((filename, slug, _('Slug already used for %s' % slugs[slug])))
-# elif slug in existing:
-# error_list.append((filename, slug, _('Slug already used in repository.')))
-# else:
-# try:
-# zip.read(filename).decode('utf-8') # test read
-# ok_list.append((filename, slug, title))
-# except UnicodeDecodeError:
-# error_list.append((filename, title, _('File should be UTF-8 encoded.')))
-# slugs[slug] = filename
-#
-# if not error_list:
-# for filename, slug, title in ok_list:
-# book = Book.create(
-# text=zip.read(filename).decode('utf-8'),
-# creator=creator,
-# slug=slug,
-# title=title,
-# )
-#
-# return render(request, "catalogue/document_upload.html", {
-# "form": form,
-# "ok_list": ok_list,
-# "skipped_list": skipped_list,
-# "error_list": error_list,
-#
-# "logout_to": '/',
-# })
-# else:
-# form = forms.DocumentsUploadForm()
-#
-# return render(request, "catalogue/document_upload.html", {
-# "form": form,
-#
-# "logout_to": '/',
-# })
-
-
-# @never_cache
-# def book_xml(request, slug):
-# book = get_object_or_404(Book, slug=slug)
-# if not book.accessible(request):
-# return HttpResponseForbidden("Not authorized.")
-# xml = book.materialize()
-#
-# response = http.HttpResponse(xml, content_type='application/xml', mimetype='application/wl+xml')
-# response['Content-Disposition'] = 'attachment; filename=%s.xml' % slug
-# return response
-
-
-# @never_cache
-# def book_txt(request, slug):
-# book = get_object_or_404(Book, slug=slug)
-# if not book.accessible(request):
-# return HttpResponseForbidden("Not authorized.")
-#
-# doc = book.wldocument()
-# text = doc.as_text().get_string()
-# response = http.HttpResponse(text, content_type='text/plain', mimetype='text/plain')
-# response['Content-Disposition'] = 'attachment; filename=%s.txt' % slug
-# return response
-
-
@never_cache
def book_html(request, pk, rev_pk=None, preview=False):
from librarian.document import Document as SST
})
-# def book(request, slug):
-# book = get_object_or_404(Book, slug=slug)
-# if not book.accessible(request):
-# return HttpResponseForbidden("Not authorized.")
-#
-# if request.user.has_perm('catalogue.change_book'):
-# if request.method == "POST":
-# form = forms.BookForm(request.POST, instance=book)
-# if form.is_valid():
-# form.save()
-# return http.HttpResponseRedirect(book.get_absolute_url())
-# else:
-# form = forms.BookForm(instance=book)
-# editable = True
-# else:
-# form = forms.ReadonlyBookForm(instance=book)
-# editable = False
-#
-# publish_error = book.publishable_error()
-# publishable = publish_error is None
-#
-# return render(request, "catalogue/book_detail.html", {
-# "book": book,
-# "publishable": publishable,
-# "publishable_error": publish_error,
-# "form": form,
-# "editable": editable,
-# })
-
-
-# @permission_required('catalogue.add_chunk')
-# def chunk_add(request, slug, chunk):
-# try:
-# doc = Chunk.get(slug, chunk)
-# except (Chunk.MultipleObjectsReturned, Chunk.DoesNotExist):
-# raise Http404
-# if not doc.book.accessible(request):
-# return HttpResponseForbidden("Not authorized.")
-#
-# if request.method == "POST":
-# form = forms.ChunkAddForm(request.POST, instance=doc)
-# if form.is_valid():
-# if request.user.is_authenticated():
-# creator = request.user
-# else:
-# creator = None
-# doc.split(creator=creator,
-# slug=form.cleaned_data['slug'],
-# title=form.cleaned_data['title'],
-# gallery_start=form.cleaned_data['gallery_start'],
-# user=form.cleaned_data['user'],
-# stage=form.cleaned_data['stage']
-# )
-#
-# return http.HttpResponseRedirect(doc.book.get_absolute_url())
-# else:
-# form = forms.ChunkAddForm(initial={
-# "slug": str(doc.number + 1),
-# "title": "cz. %d" % (doc.number + 1, ),
-# })
-#
-# return render(request, "catalogue/chunk_add.html", {
-# "chunk": doc,
-# "form": form,
-# })
-
-
-# @login_required
-# def chunk_edit(request, slug, chunk):
-# try:
-# doc = Chunk.get(slug, chunk)
-# except (Chunk.MultipleObjectsReturned, Chunk.DoesNotExist):
-# raise Http404
-# if not doc.book.accessible(request):
-# return HttpResponseForbidden("Not authorized.")
-#
-# if request.method == "POST":
-# form = forms.ChunkForm(request.POST, instance=doc)
-# if form.is_valid():
-# form.save()
-# go_next = request.GET.get('next', None)
-# if go_next:
-# go_next = urlquote_plus(unquote(iri_to_uri(go_next)), safe='/?=&')
-# else:
-# go_next = doc.book.get_absolute_url()
-# return http.HttpResponseRedirect(go_next)
-# else:
-# form = forms.ChunkForm(instance=doc)
-#
-# referer = request.META.get('HTTP_REFERER')
-# if referer:
-# parts = urlsplit(referer)
-# parts = ['', ''] + list(parts[2:])
-# go_next = urlquote_plus(urlunsplit(parts))
-# else:
-# go_next = ''
-#
-# return render(request, "catalogue/chunk_edit.html", {
-# "chunk": doc,
-# "form": form,
-# "go_next": go_next,
-# })
-
-
-# @transaction.atomic
-# @login_required
-# def chunk_mass_edit(request):
-# if request.method == 'POST':
-# ids = map(int, filter(lambda i: i.strip()!='', request.POST.get('ids').split(',')))
-# chunks = map(lambda i: Chunk.objects.get(id=i), ids)
-#
-# stage = request.POST.get('stage')
-# if stage:
-# try:
-# stage = Chunk.tag_model.objects.get(slug=stage)
-# except Chunk.DoesNotExist, e:
-# stage = None
-#
-# for c in chunks: c.stage = stage
-#
-# username = request.POST.get('user')
-# logger.info("username: %s" % username)
-# logger.info(request.POST)
-# if username:
-# try:
-# user = User.objects.get(username=username)
-# except User.DoesNotExist, e:
-# user = None
-#
-# for c in chunks: c.user = user
-#
-# status = request.POST.get('status')
-# if status:
-# books_affected = set()
-# for c in chunks:
-# if status == 'publish':
-# c.head.publishable = True
-# c.head.save()
-# elif status == 'unpublish':
-# c.head.publishable = False
-# c.head.save()
-# c.touch() # cache
-# books_affected.add(c.book)
-# for b in books_affected:
-# b.touch() # cache
-#
-# project_id = request.POST.get('project')
-# if project_id:
-# try:
-# project = Project.objects.get(pk=int(project_id))
-# except (Project.DoesNotExist, ValueError), e:
-# project = None
-# for c in chunks:
-# book = c.book
-# book.project = project
-# book.save()
-#
-# for c in chunks: c.save()
-#
-# return HttpResponse("", content_type="text/plain")
-# else:
-# raise Http404
-
-
-# @permission_required('catalogue.change_book')
-# def book_append(request, slug):
-# book = get_object_or_404(Book, slug=slug)
-# if not book.accessible(request):
-# return HttpResponseForbidden("Not authorized.")
-#
-# if request.method == "POST":
-# form = forms.BookAppendForm(book, request.POST)
-# if form.is_valid():
-# append_to = form.cleaned_data['append_to']
-# append_to.append(book)
-# return http.HttpResponseRedirect(append_to.get_absolute_url())
-# else:
-# form = forms.BookAppendForm(book)
-# return render(request, "catalogue/book_append_to.html", {
-# "book": book,
-# "form": form,
-#
-# "logout_to": '/',
-# })
-
-
@require_POST
@login_required
def publish(request, pk):
self.doc = Document.objects.get(pk=pk, deleted=False)
-class GalleryPackageView(GalleryMixin, PackageView):
-
- def get_redirect_url(self, slug):
- return reverse('catalogue_book_gallery', kwargs=dict(slug=slug))
-
-
@login_required
def fork(request, pk):
doc = get_object_or_404(Document, pk=pk, deleted=False)
name_elem = deepcopy(element)
for tag in 'extra', 'motyw', 'pa', 'pe', 'pr', 'pt', 'uwaga':
for a in name_elem.findall('.//' + tag):
- a.text=''
+ a.text = ''
del a[:]
name = etree.tostring(name_elem, method='text', encoding='utf-8').strip()
while parent[0] is not element:
del parent[0]
element, parent = parent, parent.getparent()
- chunks[:0] = [[name,
+ chunks[:0] = [[
+ name,
unicode(etree.tostring(copied, encoding='utf-8'), 'utf-8')
- ]]
+ ]]
parts = src.findall('.//naglowek_rozdzial')
- chunks[:0] = [[u'początek',
+ chunks[:0] = [[
+ u'początek',
unicode(etree.tostring(src, encoding='utf-8'), 'utf-8')
- ]]
+ ]]
for ch in chunks[1:]:
ch[1] = add_trim_begin(ch[1])
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import re
-from urllib2 import urlopen
-from django import forms
-from django.utils.translation import ugettext_lazy as _
-from cover.models import Image
-
-class ImageAddForm(forms.ModelForm):
- class Meta:
- model = Image
- exclude = []
-
- def __init__(self, *args, **kwargs):
- super(ImageAddForm, self).__init__(*args, **kwargs)
- self.fields['file'].required = self.fields['download_url'].required = self.fields['source_url'].required = False
-
- def clean_download_url(self):
- return self.cleaned_data['download_url'] or None
-
- def clean_source_url(self):
- return self.cleaned_data['source_url'] or None
-
- def clean(self):
- cleaned_data = super(ImageAddForm, self).clean()
- if not cleaned_data.get('download_url', None) and not cleaned_data.get('file', None):
- raise forms.ValidationError('No image specified')
- return cleaned_data
-
-
-class ImageEditForm(forms.ModelForm):
- """Form used for editing a Book."""
- class Meta:
- model = Image
- exclude = ['download_url']
-
-
-class ReadonlyImageEditForm(ImageEditForm):
- """Form used for not editing a Book."""
-
- def __init__(self, *args, **kwargs):
- ret = super(ReadonlyImageEditForm, self).__init__(*args, **kwargs)
- for field in self.fields.values():
- field.widget.attrs.update({"readonly": True})
- return ret
-
- def save(self, *args, **kwargs):
- raise AssertionError, "ReadonlyImageEditForm should not be saved."
-
-
-class FlickrForm(forms.Form):
- source_url = forms.URLField(label=_('Flickr URL'))
-
- def clean_source_url(self):
- def normalize_html(html):
- return re.sub('[\t\n]', '', html)
-
- url = self.cleaned_data['source_url']
- m = re.match(r'(https?://)?(www\.|secure\.)?flickr\.com/photos/(?P<author>[^/]+)/(?P<img>\d+)/?', url)
- if not m:
- raise forms.ValidationError("It doesn't look like Flickr URL.")
- author_slug, img_id = m.group('author'), m.group('img')
- base_url = "https://www.flickr.com/photos/%s/%s/" % (author_slug, img_id)
-
- try:
- html = normalize_html(urlopen(url).read().decode('utf-8'))
- except:
- raise forms.ValidationError('Error reading page.')
- match = re.search(r'<a href="([^"]*)" rel="license cc:license">Some rights reserved</a>', html)
- try:
- assert match
- license_url = match.group(1)
- self.cleaned_data['license_url'] = license_url
- re_license = re.compile(r'http://creativecommons.org/licenses/([^/]*)/([^/]*)/.*')
- m = re_license.match(license_url)
- assert m
- self.cleaned_data['license_name'] = 'CC %s %s' % (m.group(1).upper(), m.group(2))
- except AssertionError:
- raise forms.ValidationError('Error reading license name.')
-
- m = re.search(r'"ownername":"([^"]*)', html)
- if m:
- self.cleaned_data['author'] = "%s@Flickr" % m.group(1)
- else:
- raise forms.ValidationError('Error reading author name.')
-
- m = re.search(r'<h1[^>]*>(.*?)</h1>', html)
- if not m:
- raise forms.ValidationError('Error reading image title.')
- self.cleaned_data['title'] = m.group(1)
-
- url_size = base_url + "sizes/o/"
- html = normalize_html(urlopen(url_size).read().decode('utf-8'))
- m = re.search(r'<div id="allsizes-photo">\s*<img src="([^"]*)"', html)
- if m:
- self.cleaned_data['download_url'] = m.group(1)
- else:
- raise forms.ValidationError('Error reading image URL.')
- return base_url
+++ /dev/null
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the PACKAGE package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-01-26 10:36+0100\n"
-"PO-Revision-Date: 2012-06-18 12:38+0100\n"
-"Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"Language: \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
-"|| n%100>=20) ? 1 : 2)\n"
-
-#: forms.py:55
-msgid "Flickr URL"
-msgstr "URL z Flickra"
-
-#: models.py:19
-msgid "title"
-msgstr "tytuł"
-
-#: models.py:20
-msgid "author"
-msgstr "autor"
-
-#: models.py:21
-msgid "license name"
-msgstr "nazwa licencji"
-
-#: models.py:22
-msgid "license URL"
-msgstr "URL licencji"
-
-#: models.py:23
-msgid "source URL"
-msgstr "URL źródła"
-
-#: models.py:24
-msgid "image download URL"
-msgstr "URL pliku do pobrania"
-
-#: models.py:25
-msgid "file"
-msgstr "plik"
-
-#: models.py:28
-msgid "cover image"
-msgstr "obrazek na okładkę"
-
-#: models.py:29
-msgid "cover images"
-msgstr "obrazki na okładki"
-
-#: templates/cover/add_image.html:33 templates/cover/add_image.html.py:62
-msgid "Add image"
-msgstr "Dodaj obrazek"
-
-#: templates/cover/add_image.html:40
-msgid "Load from Flickr"
-msgstr "Pobierz z Flickra"
-
-#: templates/cover/image_detail.html:7
-msgid "Cover image"
-msgstr "Obrazek na okładkę"
-
-#: templates/cover/image_detail.html:23
-msgid "source"
-msgstr "źródło"
-
-#: templates/cover/image_detail.html:31
-msgid "Change"
-msgstr "Zmień"
-
-#: templates/cover/image_detail.html:37
-msgid "Used in:"
-msgstr "Użyte w:"
-
-#: templates/cover/image_detail.html:45
-msgid "None"
-msgstr "Brak"
-
-#: templates/cover/image_list.html:7
-msgid "Cover images"
-msgstr "Obrazki na okładki"
-
-#: templates/cover/image_list.html:10
-msgid "Add new"
-msgstr "Dodaj nowy"
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import re
-from urlparse import urljoin
-from django.conf import settings
-from django.core.files.base import ContentFile
-from django.db import models
-from django.db.models.signals import post_save
-from django.dispatch import receiver
-from django.utils.translation import ugettext_lazy as _
-from django.contrib.sites.models import Site
-from cover.utils import URLOpener
-
-
-class Image(models.Model):
- title = models.CharField(max_length=255, verbose_name=_('title'))
- author = models.CharField(max_length=255, verbose_name=_('author'))
- license_name = models.CharField(max_length=255, verbose_name=_('license name'))
- license_url = models.URLField(max_length=255, blank=True, verbose_name=_('license URL'))
- source_url = models.URLField(verbose_name=_('source URL'), null = True)
- download_url = models.URLField(unique=True, verbose_name=_('image download URL'), null = True)
- file = models.ImageField(upload_to='cover/image', editable=True, verbose_name=_('file'))
-
- class Meta:
- verbose_name = _('cover image')
- verbose_name_plural = _('cover images')
-
- def __unicode__(self):
- return u"%s - %s" % (self.author, self.title)
-
- @models.permalink
- def get_absolute_url(self):
- return ('cover_image', [self.id])
-
- def get_full_url(self):
- return "http://%s%s" % (Site.objects.get_current().domain, self.get_absolute_url())
-
-
-@receiver(post_save, sender=Image)
-def download_image(sender, instance, **kwargs):
- if instance.pk and not instance.file:
- t = URLOpener().open(instance.download_url).read()
- instance.file.save("%d.jpg" % instance.pk, ContentFile(t))
-
-
\ No newline at end of file
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-
-{% block add_js %}
- {{block.super}}
- <script>
- $(function() {
- var radio_buttons = $('input[type=radio][name=upload_type]'),
- image_fields = $('.upload_type input[type=text],input[type=file]');
-
- var enable_image_field = function(field) {
- field.attr('disabled', false);
- },
- disable_image_fields = function() {
- image_fields.attr('disabled', true);
- }
-
- radio_buttons.change(function() {
- var radio_button = $(this),
- related_image_field = $('#'+radio_button.attr('data-for'));
- disable_image_fields();
- enable_image_field(related_image_field);
- });
-
- /* initial state */
- disable_image_fields();
- enable_image_field($('#id_download_url'));
- });
- </script>
-{% endblock %}
-
-{% block content %}
-<h1>{% trans "Add image" %}</h1>
-
-
-<form method="post">{% csrf_token %}
-<input type="hidden" name='form_id' value="flickr" />
-<table class='editable'><tbody>
- {{ ff.as_table }}
- <tr><td></td><td><button type="submit">{% trans "Load from Flickr" %}</button></td></tr>
-</tbody></table>
-</form>
-
-<form method="post" enctype="multipart/form-data">{% csrf_token %}
-{{ form.non_field_errors }}
-<table class='editable'><tbody>
- {% for field in form %}
- {% if field.name != 'download_url' and field.name != 'file' %}
- <tr>
- <th>{{field.errors}} {{field.label}}</th>
- <td>{{field}}</td>
- </tr>
- {% endif %}
- {% endfor %}
- <tr class="upload_type">
- <th>{{ form.download_url.errors }} <input style="width: auto;" checked data-for="id_download_url" type="radio" name="upload_type" value="url"/>{{form.download_url.label}}</th>
- <td>{{form.download_url}}</td>
- <th>{{ form.file.errors }} <input style="width: auto;" data-for="id_file" type="radio" name="upload_type" value="file"/> Lub {{form.file.label}}</th>
- <td>{{form.file}}</td>
-
- </td>
- <tr><td></td><td><button type="submit">{% trans "Add image" %}</button></td></tr>
-</tbody></table>
-</form>
-
-
-{% endblock %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-{% load thumbnail %}
-{% load build_absolute_uri from common_tags %}
-
-{% block content %}
-<h1>{% trans "Cover image" %}</h1>
-
-<div style="float: right; margin-bottom:1em;">
-
-<a href="{{ object.file.url }}"><img style="width:400px"
- src="{% thumbnail object.file "400x" as thumb %}
- {{ thumb.url }}
- {% empty %}
- {{ object.file.url }}
- {% endthumbnail %}" />
- </a>
-<br/><a href="{{ object.source_url }}">{{ object.title }}</a> by {{ object.author }},
- {% if object.license_url %}<a href="{{ object.license_url }}">{% endif %}
- {{ object.license_name }}</a>
- {% if object.license_url %}</a>{% endif %}
-
-<br/>{% trans "source" %}: {{ object.download_url }}
-</div>
-
-
-{% if editable %}<form method="post">{% csrf_token %}{% endif %}
-<table class='editable'><tbody>
- {{ form.as_table }}
- {% if editable %}
- <tr><td></td><td><button type="submit">{% trans "Change" %}</button></td></tr>
- {% endif %}
-</tbody></table>
-{% if editable %}</form>{% endif %}
-
-
-<h2>{% trans "Used in:" %}</h2>
-{% if object.book_set %}
-<ul>
- {% for book in object.book_set.all %}
- <li><a href="{{ book.get_absolute_url }}">{{ book }}</a></li>
- {% endfor %}
-</ul>
-{% else %}
- <p>{% trans "None" %}</p>
-{% endif %}
-
-
-<textarea style="width:100%" rows="5">
-<dc:relation.coverImage.url xmlns:dc="http://purl.org/dc/elements/1.1/">{{ object.file.url|build_absolute_uri:request }}</dc:relation.coverImage.url>
-<dc:relation.coverImage.attribution xmlns:dc="http://purl.org/dc/elements/1.1/">{{ object.author }}, {{ object.license_name }}</dc:relation.coverImage.attribution>
-<dc:relation.coverImage.source xmlns:dc="http://purl.org/dc/elements/1.1/">{{ object.get_full_url }}</dc:relation.coverImage.source>
-</textarea>
-{% endblock %}
+++ /dev/null
-{% extends "catalogue/base.html" %}
-{% load i18n %}
-{% load thumbnail pagination_tags %}
-
-
-{% block content %}
-<h1>{% trans "Cover images" %}</h1>
-
-{% if can_add %}
- <a href="{% url 'cover_add_image' %}">{% trans "Add new" %}</a>
-{% endif %}
-
-<ul>
-{% autopaginate object_list 100 %}
-{% for image in object_list %}
- <a href="{{ image.get_absolute_url }}" style="display:inline-block; width:200px;">
-
- <img style="height: 100px"
- src="{% thumbnail image.file "x100" as thumb %}
- {{ thumb.url }}
- {% empty %}
- {{ image.file.url }}
- {% endthumbnail %}" />
- <br/>
- {{ image }}</a>
-{% endfor %}
-{% paginate %}
-</ul>
-
-{% endblock %}
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from nose.tools import *
-from django.test import TestCase
-from cover.forms import FlickrForm
-
-
-class FlickrTests(TestCase):
- def test_flickr(self):
- form = FlickrForm({"source_url": "https://www.flickr.com/photos/rczajka/6941928577/in/photostream"})
- self.assertTrue(form.is_valid())
- self.assertEqual(form.cleaned_data['source_url'], "https://www.flickr.com/photos/rczajka/6941928577/")
- self.assertEqual(form.cleaned_data['author'], "rczajka@Flickr")
- self.assertEqual(form.cleaned_data['title'], u"Pirate Stańczyk")
- self.assertEqual(form.cleaned_data['license_name'], "CC BY 2.0")
- self.assertEqual(form.cleaned_data['license_url'], "http://creativecommons.org/licenses/by/2.0/deed.en")
- self.assertEqual(form.cleaned_data['download_url'], "https://farm8.staticflickr.com/7069/6941928577_415844c58e_o.jpg")
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from django.conf.urls import patterns, url
-
-
-urlpatterns = patterns('cover.views',
- url(r'^preview/$', 'preview_from_xml', name='cover_preview'),
- url(r'^preview/(?P<book>[^/]+)/$', 'preview', name='cover_preview'),
- url(r'^preview/(?P<book>[^/]+)/(?P<chunk>[^/]+)/$',
- 'preview', name='cover_preview'),
- url(r'^preview/(?P<book>[^/]+)/(?P<chunk>[^/]+)/(?P<rev>\d+)/$',
- 'preview', name='cover_preview'),
-
- url(r'^image/$', 'image_list', name='cover_image_list'),
- url(r'^image/(?P<pk>\d+)/?$', 'image', name='cover_image'),
- url(r'^add_image/$', 'add_image', name='cover_add_image'),
-)
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-from urllib import FancyURLopener
-from django.contrib.sites.models import Site
-
-
-class URLOpener(FancyURLopener):
- @property
- def version(self):
- return 'FNP Redakcja (http://%s)' % Site.objects.get_current()
+++ /dev/null
-# -*- coding: utf-8 -*-
-#
-# This file is part of FNP-Redakcja, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
-#
-import os.path
-from django.conf import settings
-from django.contrib.auth.decorators import permission_required
-from django.http import HttpResponse, HttpResponseRedirect, Http404
-from django.shortcuts import get_object_or_404, render
-from django.views.decorators.csrf import csrf_exempt
-from django.views.decorators.http import require_POST
-from catalogue.helpers import active_tab
-from catalogue.models import Document
-from cover.models import Image
-from cover import forms
-
-
-PREVIEW_SIZE = (216, 300)
-
-
-def preview(request, book, chunk=None, rev=None):
- """Creates a cover image.
-
- If chunk and rev number are given, use version from given revision.
- If rev is not given, use publishable version.
- """
- from PIL import Image
- from librarian.cover import WLCover
- from librarian.dcparser import BookInfo
-
- chunk = Chunk.get(book, chunk)
- if rev is not None:
- try:
- revision = chunk.at_revision(rev)
- except Chunk.change_model.DoesNotExist:
- raise Http404
- else:
- revision = chunk.publishable()
- if revision is None:
- raise Http404
- xml = revision.materialize().encode('utf-8')
-
- try:
- info = BookInfo.from_string(xml)
- except:
- return HttpResponseRedirect(os.path.join(settings.STATIC_URL, "img/sample_cover.png"))
- cover = WLCover(info)
- response = HttpResponse(mimetype=cover.mime_type())
- image = cover.image().resize(PREVIEW_SIZE, Image.ANTIALIAS)
- image.save(response, cover.format)
- return response
-
-
-@csrf_exempt
-@require_POST
-def preview_from_xml(request):
- from hashlib import sha1
- from PIL import Image
- from os import makedirs
- from lxml import etree
- from librarian.cover import WLCover
- from librarian.dcparser import BookInfo
-
- xml = request.POST['xml']
- try:
- info = BookInfo.from_string(xml.encode('utf-8'))
- except:
- return HttpResponse(os.path.join(settings.STATIC_URL, "img/sample_cover.png"))
- coverid = sha1(etree.tostring(info.to_etree())).hexdigest()
- cover = WLCover(info)
-
- cover_dir = 'cover/preview'
- try:
- makedirs(os.path.join(settings.MEDIA_ROOT, cover_dir))
- except OSError:
- pass
- fname = os.path.join(cover_dir, "%s.%s" % (coverid, cover.ext()))
- image = cover.image().resize(PREVIEW_SIZE, Image.ANTIALIAS)
- image.save(os.path.join(settings.MEDIA_ROOT, fname))
- return HttpResponse(os.path.join(settings.MEDIA_URL, fname))
-
-
-@active_tab('cover')
-def image(request, pk):
- image = get_object_or_404(Image, pk=pk)
-
- if request.user.has_perm('cover.change_image'):
- if request.method == "POST":
- form = forms.ImageEditForm(request.POST, instance=image)
- if form.is_valid():
- form.save()
- return HttpResponseRedirect(image.get_absolute_url())
- else:
- form = forms.ImageEditForm(instance=image)
- editable = True
- else:
- form = forms.ReadonlyImageEditForm(instance=image)
- editable = False
-
- return render(request, "cover/image_detail.html", {
- "object": image,
- "form": form,
- "editable": editable,
- })
-
-
-@active_tab('cover')
-def image_list(request):
- objects = Image.objects.all()
- enable_add = request.user.has_perm('cover.add_image')
- return render(request, "cover/image_list.html", {
- 'object_list': Image.objects.all(),
- 'can_add': request.user.has_perm('cover.add_image'),
- })
-
-
-@permission_required('cover.add_image')
-@active_tab('cover')
-def add_image(request):
- form = ff = None
- if request.method == 'POST':
- if request.POST.get('form_id') == 'flickr':
- ff = forms.FlickrForm(request.POST)
- if ff.is_valid():
- form = forms.ImageAddForm(ff.cleaned_data)
- else:
- form = forms.ImageAddForm(request.POST, request.FILES)
- if form.is_valid():
- obj = form.save()
- return HttpResponseRedirect(obj.get_absolute_url())
- if form is None:
- form = forms.ImageAddForm()
- if ff is None:
- ff = forms.FlickrForm()
- return render(request, 'cover/add_image.html', {
- 'form': form,
- 'ff': ff,
- })
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import unicode_literals, print_function
from datetime import datetime
from django.conf import settings
from django.core.files.base import ContentFile
-from django.core.files.storage import FileSystemStorage
-from django.db import models, transaction
-from django.db.models.base import ModelBase
+from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
Gzipped text of the document is stored in a file.
"""
- author = models.ForeignKey(settings.AUTH_USER_MODEL,
- null=True, blank=True, verbose_name=_('author'))
- author_name = models.CharField(_('author name'), max_length=128,
- null=True, blank=True,
- help_text=_("Used if author is not set.")
- )
- author_email = models.CharField(_('author email'), max_length=128,
- null=True, blank=True,
- help_text=_("Used if author is not set.")
- )
+ author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, verbose_name=_('author'))
+ author_name = models.CharField(
+ _('author name'), max_length=128, null=True, blank=True, help_text=_("Used if author is not set."))
+ author_email = models.CharField(
+ _('author email'), max_length=128, null=True, blank=True, help_text=_("Used if author is not set."))
# Any other author data?
# How do we identify an author?
- parent = models.ForeignKey('self',
- null=True, blank=True, default=None,
- verbose_name=_('parent'),
- related_name="children")
+ parent = models.ForeignKey(
+ 'self', null=True, blank=True, default=None, verbose_name=_('parent'), related_name="children")
- merge_parent = models.ForeignKey('self',
- null=True, blank=True, default=None,
- verbose_name=_('merge parent'),
- related_name="merge_children")
+ merge_parent = models.ForeignKey(
+ 'self', null=True, blank=True, default=None, verbose_name=_('merge parent'), related_name="merge_children")
description = models.TextField(_('description'), blank=True, default='')
- created_at = models.DateTimeField(editable=False, db_index=True,
- default=datetime.now)
+ created_at = models.DateTimeField(editable=False, db_index=True, default=datetime.now)
class Meta:
ordering = ('created_at',)
def get_text_path(self):
if self.pk:
- return re.sub(r'([0-9a-f]{2})([^\.])', r'\1/\2', '%x.gz' % self.pk)
+ return re.sub(r'([0-9a-f]{2})([^.])', r'\1/\2', '%x.gz' % self.pk)
else:
return None
)
@classmethod
- def create(cls, text, parent=None, merge_parent=None,
- author=None, author_name=None, author_email=None,
- description=''):
+ def create(cls, text, parent=None, merge_parent=None, author=None, author_name=None, author_email=None,
+ description=''):
if text:
text = text.replace(
revs.update(self.merge_parent.get_ancestors())
return revs
+
@python_2_unicode_compatible
class Ref(models.Model):
"""A reference pointing to a specific revision."""
- revision = models.ForeignKey(Revision,
- null=True, blank=True, default=None,
- verbose_name=_('revision'),
- help_text=_("The document's revision."),
- editable=False)
+ revision = models.ForeignKey(
+ Revision, null=True, blank=True, default=None, verbose_name=_('revision'),
+ help_text=_("The document's revision."), editable=False)
def __str__(self):
return "ref:{0}->rev:{1}".format(self.id, self.revision_id)
for f in files:
os.unlink(f)
-
return result.decode('utf-8')
- def merge_with(self, revision,
- author=None, author_name=None, author_email=None,
- description="Automatic merge."):
+ def merge_with(self, revision, author=None, author_name=None, author_email=None, description="Automatic merge."):
"""Merges a given revision into the ref."""
if self.revision is None:
fast_forward = True
def materialize(self):
return self.revision.materialize() if self.revision is not None else ''
- def commit(self, text, parent=False,
- author=None, author_name=None, author_email=None,
- description=''):
+ def commit(self, text, parent=False, author=None, author_name=None, author_email=None, description=''):
"""Creates a new revision and sets it as the ref.
This will automatically merge the commit into the main branch,
if parent is not document's head.
:param unicode text: new version of the document
- :param base: parent revision (head, if not specified)
- :type base: Revision or None
:param User author: the commiter
:param unicode author_name: commiter name (if ``author`` not specified)
:param unicode author_email: commiter e-mail (if ``author`` not specified)
description=description,
parent=parent
)
- self.merge_with(rev, author=author, author_name=author_name,
- author_email=author_email)
+ self.merge_with(rev, author=author, author_name=author_name, author_email=author_email)
post_commit.send(sender=type(self), instance=self)
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import unicode_literals
from django.dispatch import Signal
post_commit = Signal(providing_args=['instance'])
-post_merge = Signal(providing_args=['fast_forward', 'instance'])
\ No newline at end of file
+post_merge = Signal(providing_args=['fast_forward', 'instance'])
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import unicode_literals
-import os
-from django.core.files.base import ContentFile, File
+from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage
try:
def get_available_name(self, name):
if self.exists(name):
self.delete(name)
- return name
\ No newline at end of file
+ return name
-from nose.tools import *
-from django.test import TestCase
-from dvcs.models import Document
-
-
-class ADocument(Document):
- class Meta:
- app_label = 'dvcs'
-
-
-class DocumentModelTests(TestCase):
-
- def assertTextEqual(self, given, expected):
- return self.assertEqual(given, expected,
- "Expected '''%s'''\n differs from text: '''%s'''" % (expected, given)
- )
-
- def test_empty_file(self):
- doc = ADocument.objects.create()
- self.assertTextEqual(doc.materialize(), u"")
-
- def test_single_commit(self):
- doc = ADocument.objects.create()
- doc.commit(text=u"Ala ma kota", description="Commit #1")
- self.assertTextEqual(doc.materialize(), u"Ala ma kota")
-
- def test_chained_commits(self):
- doc = ADocument.objects.create()
- text1 = u"""
- Line #1
- Line #2 is cool
- """
- text2 = u"""
- Line #1
- Line #2 is hot
- """
- text3 = u"""
- Line #1
- ... is hot
- Line #3 ate Line #2
- """
-
- c1 = doc.commit(description="Commit #1", text=text1)
- c2 = doc.commit(description="Commit #2", text=text2)
- c3 = doc.commit(description="Commit #3", text=text3)
-
- self.assertTextEqual(doc.materialize(), text3)
- self.assertTextEqual(doc.materialize(change=c3), text3)
- self.assertTextEqual(doc.materialize(change=c2), text2)
- self.assertTextEqual(doc.materialize(change=c1), text1)
-
- def test_parallel_commit_noconflict(self):
- doc = ADocument.objects.create()
- text1 = u"""
- Line #1
- Line #2
- """
- text2 = u"""
- Line #1 is hot
- Line #2
- """
- text3 = u"""
- Line #1
- Line #2
- Line #3
- """
- text_merged = u"""
- Line #1 is hot
- Line #2
- Line #3
- """
-
- base = doc.commit(description="Commit #1", text=text1)
- c1 = doc.commit(description="Commit #2", text=text2)
- commits = doc.change_set.count()
- c2 = doc.commit(description="Commit #3", text=text3, parent=base)
- self.assertEqual(doc.change_set.count(), commits + 2,
- u"Parallel commits should create an additional merge commit")
- self.assertTextEqual(doc.materialize(), text_merged)
-
- def test_parallel_commit_conflict(self):
- doc = ADocument.objects.create()
- text1 = u"""
- Line #1
- Line #2
- Line #3
- """
- text2 = u"""
- Line #1
- Line #2 is hot
- Line #3
- """
- text3 = u"""
- Line #1
- Line #2 is cool
- Line #3
- """
- text_merged = u"""
- Line #1
-<<<<<<<
- Line #2 is hot
-=======
- Line #2 is cool
->>>>>>>
- Line #3
- """
- base = doc.commit(description="Commit #1", text=text1)
- c1 = doc.commit(description="Commit #2", text=text2)
- commits = doc.change_set.count()
- c2 = doc.commit(description="Commit #3", text=text3, parent=base)
- self.assertEqual(doc.change_set.count(), commits + 2,
- u"Parallel commits should create an additional merge commit")
- self.assertTextEqual(doc.materialize(), text_merged)
-
-
- def test_multiple_parallel_commits(self):
- text_a1 = u"""
- Line #1
-
- Line #2
-
- Line #3
- """
- text_a2 = u"""
- Line #1 *
-
- Line #2
-
- Line #3
- """
- text_b1 = u"""
- Line #1
-
- Line #2 **
-
- Line #3
- """
- text_c1 = u"""
- Line #1
-
- Line #2
-
- Line #3 ***
- """
- text_merged = u"""
- Line #1 *
-
- Line #2 **
-
- Line #3 ***
- """
-
-
- doc = ADocument.objects.create()
- c1 = doc.commit(description="Commit A1", text=text_a1)
- c2 = doc.commit(description="Commit A2", text=text_a2, parent=c1)
- c3 = doc.commit(description="Commit B1", text=text_b1, parent=c1)
- c4 = doc.commit(description="Commit C1", text=text_c1, parent=c1)
- self.assertTextEqual(doc.materialize(), text_merged)
-
-
- def test_prepend_history(self):
- doc1 = ADocument.objects.create()
- doc2 = ADocument.objects.create()
- doc1.commit(text='Commit 1')
- doc2.commit(text='Commit 2')
- doc2.prepend_history(doc1)
- self.assertEqual(ADocument.objects.all().count(), 1)
- self.assertTextEqual(doc2.at_revision(1).materialize(), 'Commit 1')
- self.assertTextEqual(doc2.materialize(), 'Commit 2')
-
- def test_prepend_to_self(self):
- doc = ADocument.objects.create()
- doc.commit(text='Commit 1')
- with self.assertRaises(AssertionError):
- doc.prepend_history(doc)
- self.assertTextEqual(doc.materialize(), 'Commit 1')
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import unicode_literals
-VERSION='0.1'
+VERSION = '0.1'
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
at = escape(_('at'))
dot = escape(_('dot'))
mangled = "%s %s %s" % (name, at, (' %s ' % dot).join(domain.split('.')))
- return mark_safe("<a class='mangled' data-addr1='%(name)s' "
+ return mark_safe(
+ "<a class='mangled' data-addr1='%(name)s' "
"data-addr2='%(domain)s'>%(mangled)s</a>" % {
'name': name.encode('rot13'),
'domain': domain.encode('rot13'),
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import forms
+
class UploadForm(forms.Form):
files = forms.FileField()
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import template
register = template.Library()
+
@register.simple_tag
def upload_js():
return """
<td class="name"><span>{%=file.name%}</span></td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
{% if (file.error) { %}
- <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
+ <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span>
+ {%=locale.fileupload.errors[file.error] || file.error%}</td>
{% } else if (o.files.valid && !i) { %}
<td>
- <div class="progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>
+ <div class="progress progress-success progress-striped active">
+ <div class="bar" style="width:0%;"></div>
+ </div>
</td>
<td class="start">{% if (!o.options.autoUpload) { %}
<button class="btn btn-success">
<td></td>
<td class="name"><span>{%=file.name%}</span></td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
- <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
+ <td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span>
+ {%=locale.fileupload.errors[file.error] || file.error%}</td>
{% } else { %}
<td class="preview">{% if (file.thumbnail_url) { %}
- <a href="{%=file.url%}" title="{%=file.name%}" rel="gallery" download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
+ <a href="{%=file.url%}" title="{%=file.name%}" rel="gallery"
+ download="{%=file.name%}"><img src="{%=file.thumbnail_url%}"></a>
{% } %}</td>
<td class="name">
- <a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}" download="{%=file.name%}">{%=file.name%}</a>
+ <a href="{%=file.url%}" title="{%=file.name%}" rel="{%=file.thumbnail_url&&'gallery'%}"
+ download="{%=file.name%}">{%=file.name%}</a>
</td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
<td colspan="2"></td>
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.conf.urls import patterns, url
from fileupload.views import UploadView
-urlpatterns = patterns('',
+urlpatterns = patterns(
+ '',
url(r'^(?P<path>(?:.*/)?)$', UploadView.as_view(), name='fileupload'),
)
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
import json
import os
-from zipfile import ZipFile
from urllib import quote
from django.conf import settings
-from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
+from django.http import HttpResponse, Http404
from django.utils.decorators import method_decorator
from django.views.decorators.vary import vary_on_headers
-from django.views.generic import FormView, View, RedirectView
+from django.views.generic import FormView
from .forms import UploadForm
content = json.dumps(obj)
super(JSONResponse, self).__init__(content, mimetype, *args, **kwargs)
+
class UploadViewMixin(object):
def get_safe_path(self, filename=""):
"""Finds absolute filesystem path of the browsed dir of file.
raise Http404
return path
+
class UploadView(UploadViewMixin, FormView):
template_name = "fileupload/picture_form.html"
form_class = UploadForm
directory = os.path.dirname(directory)
now_path = (os.path.dirname(now_path))
while directory:
- crumbs.insert(0, (os.path.basename(directory), now_path+'/'))
+ crumbs.insert(0, (os.path.basename(directory), now_path + '/'))
directory = os.path.dirname(directory)
now_path = os.path.dirname(now_path)
crumbs.insert(0, ('media', now_path))
quote(f.encode('utf-8'))),
'delete_type': "DELETE"
})
- thumbnail_url = thumbnail(self.get_directory() + f),
files.append(file_info)
return JSONResponse(files)
else:
'name': f.name,
'url': self.get_url(f.name),
'thumbnail_url': thumbnail(self.get_directory() + f.name),
- 'delete_url': "%s?file=%s" % (
- self.request.get_full_path(),
- quote(f.name.encode('utf-8'))),
+ 'delete_url': "%s?file=%s" % (
+ self.request.get_full_path(),
+ quote(f.name.encode('utf-8'))),
'delete_type': "DELETE"
})
response = JSONResponse(data)
response = JSONResponse(True)
response['Content-Disposition'] = 'inline; filename=files.json'
return response
-
-
-class PackageView(UploadViewMixin, RedirectView):
- def dispatch(self, request, *args, **kwargs):
- self.object = self.get_object(request, *args, **kwargs)
- path = self.get_safe_path()
- with ZipFile(os.path.join(path, 'package.zip'), 'w') as zip_file:
- for f in os.listdir(path):
- if f == 'package.zip':
- continue
- zip_file.write(os.path.join(path, f), arcname = f)
- return super(PackageView, self).dispatch(request, *args, **kwargs)
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.contrib import admin
from organizations import models
admin.site.register(models.Organization)
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import forms
from .models import Organization, UserCard, countries
+
class OrganizationForm(forms.ModelForm):
cts = countries
model = Organization
exclude = ['_html']
+
class UserCardForm(forms.ModelForm):
cts = countries
'first_name': kwargs['instance'].user.first_name,
'last_name': kwargs['instance'].user.last_name,
}
- return super(UserCardForm, self).__init__(*args, **kwargs)
+ super(UserCardForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
self.instance.user.first_name = self.cleaned_data.get('first_name', '')
self.instance.user.last_name = self.cleaned_data.get('last_name', '')
self.instance.user.save()
return super(UserCardForm, self).save(*args, **kwargs)
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import template
from embeder import embed
register = template.Library()
+
@register.assignment_tag
def urlinfo(url):
try:
from organizations import views
-urlpatterns = patterns('',
+urlpatterns = patterns(
+ '',
url(r'^$', views.organizations, name="organizations"),
url(r'^new/$', views.org_new, name="organizations_new"),
url(r'^(?P<pk>\d+)/$', views.main, name="organizations_main"),
-# Create your views here.
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.shortcuts import render, redirect
-from django.http import HttpResponse, Http404
-#from django.views.decorators import require_post
+from django.http import Http404
from .forms import OrganizationForm, UserCardForm
from .models import Organization, Membership, UserCard
+
@login_required
def org_new(request):
if request.method == 'POST':
'am_member': am_member,
})
+
def user_card(request, pk):
try:
user = User.objects.get(pk=pk)
return render(request, 'organizations/join.html', {'org': org})
+
@login_required
-#@POST_required
def membership(request, pk):
try:
org = Organization.objects.get(pk=pk)
from django import forms
from django.utils.translation import ugettext_lazy as _
-from catalogue.models import Document
from catalogue.constants import STAGES
)
stage = forms.ChoiceField(
- choices = [(s, s) for s in STAGES],
+ choices=[(s, s) for s in STAGES],
required=False,
label=_(u"Stage"),
help_text=_(u"If completed a work stage, change to another one."),
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
- r = super(DocumentTextSaveForm, self).__init__(*args, **kwargs)
+ super(DocumentTextSaveForm, self).__init__(*args, **kwargs)
if user and user.is_authenticated():
self.fields['author_name'].required = False
self.fields['author_email'].required = False
- return r
class DocumentTextRevertForm(forms.Form):
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from datetime import datetime
from functools import wraps
import json
def filter_line(line):
- return DIFF_RE.sub(diff_replace, html_escape(line)).replace('\x01', '</span>')
+ return DIFF_RE.sub(diff_replace, html_escape(line)).replace('\x01', '</span>')
def format_changeset(a, b, change):
- return (a[0], filter_line(a[1]), b[0], filter_line(b[1]), change)
+ return a[0], filter_line(a[1]), b[0], filter_line(b[1]), change
def html_diff_table(la, lb, context=None):
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.conf import settings
GALLERY_URL = settings.MEDIA_URL + 'images/'
+++ /dev/null
-/* record log messages for testing */
-// var logAllIds = function() {
-// var allTags = document.head.getElementsByTagName('style');
-// var ids = [];
-// for (var tg = 0; tg < allTags.length; tg++) {
-// var tag = allTags[tg];
-// if (tag.id) {
-// console.log(tag.id);
-// }
-// }
-// };
-
-var logMessages = [],
- realConsoleLog = console.log;
-console.log = function(msg) {
- logMessages.push(msg);
- realConsoleLog.call(console, msg);
-};
-
-var testLessEqualsInDocument = function() {
- testLessInDocument(testSheet);
-};
-
-var testLessErrorsInDocument = function(isConsole) {
- testLessInDocument(isConsole ? testErrorSheetConsole : testErrorSheet);
-};
-
-var testLessInDocument = function(testFunc) {
- var links = document.getElementsByTagName('link'),
- typePattern = /^text\/(x-)?less$/;
-
- for (var i = 0; i < links.length; i++) {
- if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
- (links[i].type.match(typePattern)))) {
- testFunc(links[i]);
- }
- }
-};
-
-var testSheet = function(sheet) {
- it(sheet.id + " should match the expected output", function() {
- var lessOutputId = sheet.id.replace("original-", ""),
- expectedOutputId = "expected-" + lessOutputId,
- lessOutputObj,
- lessOutput,
- expectedOutputHref = document.getElementById(expectedOutputId).href,
- expectedOutput = loadFile(expectedOutputHref);
-
- // Browser spec generates less on the fly, so we need to loose control
- waitsFor(function() {
- lessOutputObj = document.getElementById(lessOutputId);
- // the type condition is necessary because of inline browser tests
- return lessOutputObj !== null && lessOutputObj.type === "text/css";
- }, "generation of " + lessOutputId + "", 700);
-
- runs(function() {
- lessOutput = lessOutputObj.innerText;
- });
-
- waitsFor(function() {
- return expectedOutput.loaded;
- }, "failed to load expected outout", 10000);
-
- runs(function() {
- // use sheet to do testing
- expect(expectedOutput.text).toEqual(lessOutput);
- });
- });
-};
-
-//TODO: do it cleaner - the same way as in css
-
-function extractId(href) {
- return href.replace(/^[a-z-]+:\/+?[^\/]+/, '') // Remove protocol & domain
- .replace(/^\//, '') // Remove root /
- .replace(/\.[a-zA-Z]+$/, '') // Remove simple extension
- .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
- .replace(/\./g, ':'); // Replace dots with colons(for valid id)
-}
-
-var testErrorSheet = function(sheet) {
- it(sheet.id + " should match an error", function() {
- var lessHref = sheet.href,
- id = "less-error-message:" + extractId(lessHref),
- // id = sheet.id.replace(/^original-less:/, "less-error-message:"),
- errorHref = lessHref.replace(/.less$/, ".txt"),
- errorFile = loadFile(errorHref),
- actualErrorElement,
- actualErrorMsg;
-
- // Less.js sets 10ms timer in order to add error message on top of page.
- waitsFor(function() {
- actualErrorElement = document.getElementById(id);
- return actualErrorElement !== null;
- }, "error message was not generated", 70);
-
- runs(function() {
- actualErrorMsg = actualErrorElement.innerText
- .replace(/\n\d+/g, function(lineNo) {
- return lineNo + " ";
- })
- .replace(/\n\s*in /g, " in ")
- .replace("\n\n", "\n");
- });
-
- waitsFor(function() {
- return errorFile.loaded;
- }, "failed to load expected outout", 10000);
-
- runs(function() {
- var errorTxt = errorFile.text
- .replace("{path}", "")
- .replace("{pathrel}", "")
- .replace("{pathhref}", "http://localhost:8081/test/less/errors/")
- .replace("{404status}", " (404)");
- expect(errorTxt).toEqual(actualErrorMsg);
- if (errorTxt == actualErrorMsg) {
- actualErrorElement.style.display = "none";
- }
- });
- });
-};
-
-var testErrorSheetConsole = function(sheet) {
- it(sheet.id + " should match an error", function() {
- var lessHref = sheet.href,
- id = sheet.id.replace(/^original-less:/, "less-error-message:"),
- errorHref = lessHref.replace(/.less$/, ".txt"),
- errorFile = loadFile(errorHref),
- actualErrorElement = document.getElementById(id),
- actualErrorMsg = logMessages[logMessages.length - 1];
-
- describe("the error", function() {
- expect(actualErrorElement).toBe(null);
-
- });
-
- /*actualErrorMsg = actualErrorElement.innerText
- .replace(/\n\d+/g, function(lineNo) { return lineNo + " "; })
- .replace(/\n\s*in /g, " in ")
- .replace("\n\n", "\n");*/
-
- waitsFor(function() {
- return errorFile.loaded;
- }, "failed to load expected outout", 10000);
-
- runs(function() {
- var errorTxt = errorFile.text
- .replace("{path}", "")
- .replace("{pathrel}", "")
- .replace("{pathhref}", "http://localhost:8081/browser/less/")
- .replace("{404status}", " (404)")
- .trim();
- expect(errorTxt).toEqual(actualErrorMsg);
- });
- });
-};
-
-var loadFile = function(href) {
- var request = new XMLHttpRequest(),
- response = {
- loaded: false,
- text: ""
- };
- request.open('GET', href, true);
- request.onload = function(e) {
- response.text = request.response.replace(/\r/g, "");
- response.loaded = true;
- };
- request.send();
- return response;
-};
-
-(function() {
- var jasmineEnv = jasmine.getEnv();
- jasmineEnv.updateInterval = 1000;
-
- var htmlReporter = new jasmine.HtmlReporter();
-
- jasmineEnv.addReporter(htmlReporter);
-
- jasmineEnv.specFilter = function(spec) {
- return htmlReporter.specFilter(spec);
- };
-
- var currentWindowOnload = window.onload;
-
- window.onload = function() {
- if (currentWindowOnload) {
- currentWindowOnload();
- }
- execJasmine();
- };
-
- function execJasmine() {
- setTimeout(function() {
- jasmineEnv.execute();
- }, 3000);
- }
-
-})();
\ No newline at end of file
+++ /dev/null
-.test {
- color: #ff0000;
-}
+++ /dev/null
-.testisimported {
- color: gainsboro;
-}
-.test {
- color1: #008000;
- color2: #800080;
-}
+++ /dev/null
-@import "http://localhost:8081/test/browser/less/imports/modify-this.css";
-@import "http://localhost:8081/test/browser/less/imports/modify-again.css";
-.modify {
- my-url: url("http://localhost:8081/test/browser/less/imports/a.png");
-}
-.modify {
- my-url: url("http://localhost:8081/test/browser/less/imports/b.png");
-}
-@font-face {
- src: local(Futura-Medium), url(http://localhost:8081/test/browser/less/relative-urls/fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(http://localhost:8081/test/browser/less/relative-urls/images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-.comma-delimited {
- background: url(http://localhost:8081/test/browser/less/relative-urls/bg.jpg) no-repeat, url(http://localhost:8081/test/browser/less/relative-urls/bg.png) repeat-x top left, url(http://localhost:8081/test/browser/less/relative-urls/bg);
-}
-.values {
- url: url('http://localhost:8081/test/browser/less/relative-urls/Trebuchet');
-}
+++ /dev/null
-@import "https://www.github.com/cloudhead/imports/modify-this.css";
-@import "https://www.github.com/cloudhead/imports/modify-again.css";
-.modify {
- my-url: url("https://www.github.com/cloudhead/imports/a.png");
-}
-.modify {
- my-url: url("https://www.github.com/cloudhead/imports/b.png");
-}
-@font-face {
- src: local(Futura-Medium), url(https://www.github.com/cloudhead/less.js/fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(https://www.github.com/cloudhead/less.js/images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-.comma-delimited {
- background: url(https://www.github.com/cloudhead/less.js/bg.jpg) no-repeat, url(https://www.github.com/cloudhead/less.js/bg.png) repeat-x top left, url(https://www.github.com/cloudhead/less.js/bg);
-}
-.values {
- url: url('https://www.github.com/cloudhead/less.js/Trebuchet');
-}
+++ /dev/null
-/*@import "https://www.github.com/modify-this.css";*/
-/*@import "https://www.github.com/modify-again.css";*/
-.modify {
- my-url: url("https://www.github.com/a.png");
-}
-.modify {
- my-url: url("https://www.github.com/b.png");
-}
-@font-face {
- src: local(Futura-Medium), url(https://www.github.com/fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(https://www.github.com/images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ukg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-.comma-delimited {
- background: url(https://www.github.com/bg.jpg) no-repeat, url(https://www.github.com/bg.png) repeat-x top left, url(https://www.github.com/bg);
-}
-.values {
- url: url('https://www.github.com/Trebuchet');
-}
+++ /dev/null
-/*@import "http://localhost:8081/test/browser/less/modify-this.css";*/
-/*@import "http://localhost:8081/test/browser/less/modify-again.css";*/
-.modify {
- my-url: url("http://localhost:8081/test/browser/less/a.png");
-}
-.modify {
- my-url: url("http://localhost:8081/test/browser/less/b.png");
-}
-@font-face {
- src: local(Futura-Medium), url(http://localhost:8081/test/browser/less/fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(http://localhost:8081/test/browser/less/images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ukg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-.comma-delimited {
- background: url(http://localhost:8081/test/browser/less/bg.jpg) no-repeat, url(http://localhost:8081/test/browser/less/bg.png) repeat-x top left, url(http://localhost:8081/test/browser/less/bg);
-}
-.values {
- url: url('http://localhost:8081/test/browser/less/Trebuchet');
-}
-#data-uri {
- uri: url('http://localhost:8081/test/data/image.jpg');
-}
-#data-uri-guess {
- uri: url('http://localhost:8081/test/data/image.jpg');
-}
-#data-uri-ascii {
- uri-1: url('http://localhost:8081/test/data/page.html');
- uri-2: url('http://localhost:8081/test/data/page.html');
-}
-#data-uri-toobig {
- uri: url('http://localhost:8081/test/data/data-uri-fail.png');
-}
-#svg-functions {
- background-image: url('data:image/svg+xml,<?xml version="1.0" ?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"><linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#000000"/><stop offset="100%" stop-color="#ffffff"/></linearGradient><rect x="0" y="0" width="1" height="1" fill="url(#gradient)" /></svg>');
- background-image: url('data:image/svg+xml,<?xml version="1.0" ?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"><linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#000000"/><stop offset="3%" stop-color="#ffa500"/><stop offset="100%" stop-color="#ffffff"/></linearGradient><rect x="0" y="0" width="1" height="1" fill="url(#gradient)" /></svg>');
- background-image: url('data:image/svg+xml,<?xml version="1.0" ?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none"><linearGradient id="gradient" gradientUnits="userSpaceOnUse" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="1%" stop-color="#c4c4c4"/><stop offset="3%" stop-color="#ffa500"/><stop offset="5%" stop-color="#008000"/><stop offset="95%" stop-color="#ffffff"/></linearGradient><rect x="0" y="0" width="1" height="1" fill="url(#gradient)" /></svg>');
-}
+++ /dev/null
-/*
- PhantomJS does not implement bind. this is from
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
- */
-if (!Function.prototype.bind) {
- Function.prototype.bind = function (oThis) {
- if (typeof this !== "function") {
- // closest thing possible to the ECMAScript 5 internal IsCallable function
- throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
- }
-
- var aArgs = Array.prototype.slice.call(arguments, 1),
- fToBind = this,
- fNOP = function () {},
- fBound = function () {
- return fToBind.apply(this instanceof fNOP && oThis
- ? this
- : oThis,
- aArgs.concat(Array.prototype.slice.call(arguments)));
- };
-
- fNOP.prototype = this.prototype;
- fBound.prototype = new fNOP();
-
- return fBound;
- };
-}
\ No newline at end of file
+++ /dev/null
-jasmine.HtmlReporterHelpers = {};
-
-jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
- var el = document.createElement(type);
-
- for (var i = 2; i < arguments.length; i++) {
- var child = arguments[i];
-
- if (typeof child === 'string') {
- el.appendChild(document.createTextNode(child));
- } else {
- if (child) {
- el.appendChild(child);
- }
- }
- }
-
- for (var attr in attrs) {
- if (attr == "className") {
- el[attr] = attrs[attr];
- } else {
- el.setAttribute(attr, attrs[attr]);
- }
- }
-
- return el;
-};
-
-jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
- var results = child.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.skipped) {
- status = 'skipped';
- }
-
- return status;
-};
-
-jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
- var parentDiv = this.dom.summary;
- var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
- var parent = child[parentSuite];
-
- if (parent) {
- if (typeof this.views.suites[parent.id] == 'undefined') {
- this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
- }
- parentDiv = this.views.suites[parent.id].element;
- }
-
- parentDiv.appendChild(childElement);
-};
-
-
-jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
- for(var fn in jasmine.HtmlReporterHelpers) {
- ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
- }
-};
-
-jasmine.HtmlReporter = function(_doc) {
- var self = this;
- var doc = _doc || window.document;
-
- var reporterView;
-
- var dom = {};
-
- // Jasmine Reporter Public Interface
- self.logRunningSpecs = false;
-
- self.reportRunnerStarting = function(runner) {
- var specs = runner.specs() || [];
-
- if (specs.length == 0) {
- return;
- }
-
- createReporterDom(runner.env.versionString());
- doc.body.appendChild(dom.reporter);
- setExceptionHandling();
-
- reporterView = new jasmine.HtmlReporter.ReporterView(dom);
- reporterView.addSpecs(specs, self.specFilter);
- };
-
- self.reportRunnerResults = function(runner) {
- reporterView && reporterView.complete();
- };
-
- self.reportSuiteResults = function(suite) {
- reporterView.suiteComplete(suite);
- };
-
- self.reportSpecStarting = function(spec) {
- if (self.logRunningSpecs) {
- self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
- }
- };
-
- self.reportSpecResults = function(spec) {
- reporterView.specComplete(spec);
- };
-
- self.log = function() {
- var console = jasmine.getGlobal().console;
- if (console && console.log) {
- if (console.log.apply) {
- console.log.apply(console, arguments);
- } else {
- console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
- }
- }
- };
-
- self.specFilter = function(spec) {
- if (!focusedSpecName()) {
- return true;
- }
-
- return spec.getFullName().indexOf(focusedSpecName()) === 0;
- };
-
- return self;
-
- function focusedSpecName() {
- var specName;
-
- (function memoizeFocusedSpec() {
- if (specName) {
- return;
- }
-
- var paramMap = [];
- var params = jasmine.HtmlReporter.parameters(doc);
-
- for (var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
- }
-
- specName = paramMap.spec;
- })();
-
- return specName;
- }
-
- function createReporterDom(version) {
- dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
- dom.banner = self.createDom('div', { className: 'banner' },
- self.createDom('span', { className: 'title' }, "Jasmine "),
- self.createDom('span', { className: 'version' }, version)),
-
- dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
- dom.alert = self.createDom('div', {className: 'alert'},
- self.createDom('span', { className: 'exceptions' },
- self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
- self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
- dom.results = self.createDom('div', {className: 'results'},
- dom.summary = self.createDom('div', { className: 'summary' }),
- dom.details = self.createDom('div', { id: 'details' }))
- );
- }
-
- function noTryCatch() {
- return window.location.search.match(/catch=false/);
- }
-
- function searchWithCatch() {
- var params = jasmine.HtmlReporter.parameters(window.document);
- var removed = false;
- var i = 0;
-
- while (!removed && i < params.length) {
- if (params[i].match(/catch=/)) {
- params.splice(i, 1);
- removed = true;
- }
- i++;
- }
- if (jasmine.CATCH_EXCEPTIONS) {
- params.push("catch=false");
- }
-
- return params.join("&");
- }
-
- function setExceptionHandling() {
- var chxCatch = document.getElementById('no_try_catch');
-
- if (noTryCatch()) {
- chxCatch.setAttribute('checked', true);
- jasmine.CATCH_EXCEPTIONS = false;
- }
- chxCatch.onclick = function() {
- window.location.search = searchWithCatch();
- };
- }
-};
-jasmine.HtmlReporter.parameters = function(doc) {
- var paramStr = doc.location.search.substring(1);
- var params = [];
-
- if (paramStr.length > 0) {
- params = paramStr.split('&');
- }
- return params;
-}
-jasmine.HtmlReporter.sectionLink = function(sectionName) {
- var link = '?';
- var params = [];
-
- if (sectionName) {
- params.push('spec=' + encodeURIComponent(sectionName));
- }
- if (!jasmine.CATCH_EXCEPTIONS) {
- params.push("catch=false");
- }
- if (params.length > 0) {
- link += params.join("&");
- }
-
- return link;
-};
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
-jasmine.HtmlReporter.ReporterView = function(dom) {
- this.startedAt = new Date();
- this.runningSpecCount = 0;
- this.completeSpecCount = 0;
- this.passedCount = 0;
- this.failedCount = 0;
- this.skippedCount = 0;
-
- this.createResultsMenu = function() {
- this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
- this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
- ' | ',
- this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
-
- this.summaryMenuItem.onclick = function() {
- dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
- };
-
- this.detailsMenuItem.onclick = function() {
- showDetails();
- };
- };
-
- this.addSpecs = function(specs, specFilter) {
- this.totalSpecCount = specs.length;
-
- this.views = {
- specs: {},
- suites: {}
- };
-
- for (var i = 0; i < specs.length; i++) {
- var spec = specs[i];
- this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
- if (specFilter(spec)) {
- this.runningSpecCount++;
- }
- }
- };
-
- this.specComplete = function(spec) {
- this.completeSpecCount++;
-
- if (isUndefined(this.views.specs[spec.id])) {
- this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
- }
-
- var specView = this.views.specs[spec.id];
-
- switch (specView.status()) {
- case 'passed':
- this.passedCount++;
- break;
-
- case 'failed':
- this.failedCount++;
- break;
-
- case 'skipped':
- this.skippedCount++;
- break;
- }
-
- specView.refresh();
- this.refresh();
- };
-
- this.suiteComplete = function(suite) {
- var suiteView = this.views.suites[suite.id];
- if (isUndefined(suiteView)) {
- return;
- }
- suiteView.refresh();
- };
-
- this.refresh = function() {
-
- if (isUndefined(this.resultsMenu)) {
- this.createResultsMenu();
- }
-
- // currently running UI
- if (isUndefined(this.runningAlert)) {
- this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" });
- dom.alert.appendChild(this.runningAlert);
- }
- this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
-
- // skipped specs UI
- if (isUndefined(this.skippedAlert)) {
- this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" });
- }
-
- this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
- if (this.skippedCount === 1 && isDefined(dom.alert)) {
- dom.alert.appendChild(this.skippedAlert);
- }
-
- // passing specs UI
- if (isUndefined(this.passedAlert)) {
- this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" });
- }
- this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
-
- // failing specs UI
- if (isUndefined(this.failedAlert)) {
- this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
- }
- this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
-
- if (this.failedCount === 1 && isDefined(dom.alert)) {
- dom.alert.appendChild(this.failedAlert);
- dom.alert.appendChild(this.resultsMenu);
- }
-
- // summary info
- this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
- this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
- };
-
- this.complete = function() {
- dom.alert.removeChild(this.runningAlert);
-
- this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
- if (this.failedCount === 0) {
- dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
- } else {
- showDetails();
- }
-
- dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
- };
-
- return this;
-
- function showDetails() {
- if (dom.reporter.className.search(/showDetails/) === -1) {
- dom.reporter.className += " showDetails";
- }
- }
-
- function isUndefined(obj) {
- return typeof obj === 'undefined';
- }
-
- function isDefined(obj) {
- return !isUndefined(obj);
- }
-
- function specPluralizedFor(count) {
- var str = count + " spec";
- if (count > 1) {
- str += "s"
- }
- return str;
- }
-
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
-
-
-jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
- this.spec = spec;
- this.dom = dom;
- this.views = views;
-
- this.symbol = this.createDom('li', { className: 'pending' });
- this.dom.symbolSummary.appendChild(this.symbol);
-
- this.summary = this.createDom('div', { className: 'specSummary' },
- this.createDom('a', {
- className: 'description',
- href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()),
- title: this.spec.getFullName()
- }, this.spec.description)
- );
-
- this.detail = this.createDom('div', { className: 'specDetail' },
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
- title: this.spec.getFullName()
- }, this.spec.getFullName())
- );
-};
-
-jasmine.HtmlReporter.SpecView.prototype.status = function() {
- return this.getSpecStatus(this.spec);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
- this.symbol.className = this.status();
-
- switch (this.status()) {
- case 'skipped':
- break;
-
- case 'passed':
- this.appendSummaryToSuiteDiv();
- break;
-
- case 'failed':
- this.appendSummaryToSuiteDiv();
- this.appendFailureDetail();
- break;
- }
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
- this.summary.className += ' ' + this.status();
- this.appendToSummary(this.spec, this.summary);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
- this.detail.className += ' ' + this.status();
-
- var resultItems = this.spec.results().getItems();
- var messagesDiv = this.createDom('div', { className: 'messages' });
-
- for (var i = 0; i < resultItems.length; i++) {
- var result = resultItems[i];
-
- if (result.type == 'log') {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
- } else if (result.type == 'expect' && result.passed && !result.passed()) {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
- if (result.trace.stack) {
- messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
- }
- }
- }
-
- if (messagesDiv.childNodes.length > 0) {
- this.detail.appendChild(messagesDiv);
- this.dom.details.appendChild(this.detail);
- }
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
- this.suite = suite;
- this.dom = dom;
- this.views = views;
-
- this.element = this.createDom('div', { className: 'suite' },
- this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description)
- );
-
- this.appendToSummary(this.suite, this.element);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.status = function() {
- return this.getSpecStatus(this.suite);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
- this.element.className += " " + this.status();
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
-
-/* @deprecated Use jasmine.HtmlReporter instead
- */
-jasmine.TrivialReporter = function(doc) {
- this.document = doc || document;
- this.suiteDivs = {};
- this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
- var el = document.createElement(type);
-
- for (var i = 2; i < arguments.length; i++) {
- var child = arguments[i];
-
- if (typeof child === 'string') {
- el.appendChild(document.createTextNode(child));
- } else {
- if (child) { el.appendChild(child); }
- }
- }
-
- for (var attr in attrs) {
- if (attr == "className") {
- el[attr] = attrs[attr];
- } else {
- el.setAttribute(attr, attrs[attr]);
- }
- }
-
- return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
- var showPassed, showSkipped;
-
- this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
- this.createDom('div', { className: 'banner' },
- this.createDom('div', { className: 'logo' },
- this.createDom('span', { className: 'title' }, "Jasmine"),
- this.createDom('span', { className: 'version' }, runner.env.versionString())),
- this.createDom('div', { className: 'options' },
- "Show ",
- showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
- showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
- )
- ),
-
- this.runnerDiv = this.createDom('div', { className: 'runner running' },
- this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
- this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
- this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
- );
-
- this.document.body.appendChild(this.outerDiv);
-
- var suites = runner.suites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- var suiteDiv = this.createDom('div', { className: 'suite' },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
- this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
- this.suiteDivs[suite.id] = suiteDiv;
- var parentDiv = this.outerDiv;
- if (suite.parentSuite) {
- parentDiv = this.suiteDivs[suite.parentSuite.id];
- }
- parentDiv.appendChild(suiteDiv);
- }
-
- this.startedAt = new Date();
-
- var self = this;
- showPassed.onclick = function(evt) {
- if (showPassed.checked) {
- self.outerDiv.className += ' show-passed';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
- }
- };
-
- showSkipped.onclick = function(evt) {
- if (showSkipped.checked) {
- self.outerDiv.className += ' show-skipped';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
- }
- };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
- var results = runner.results();
- var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
- this.runnerDiv.setAttribute("class", className);
- //do it twice for IE
- this.runnerDiv.setAttribute("className", className);
- var specs = runner.specs();
- var specCount = 0;
- for (var i = 0; i < specs.length; i++) {
- if (this.specFilter(specs[i])) {
- specCount++;
- }
- }
- var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
- message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
- this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
- this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
- var results = suite.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.totalCount === 0) { // todo: change this to check results.skipped
- status = 'skipped';
- }
- this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
- if (this.logRunningSpecs) {
- this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
- }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
- var results = spec.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.skipped) {
- status = 'skipped';
- }
- var specDiv = this.createDom('div', { className: 'spec ' + status },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(spec.getFullName()),
- title: spec.getFullName()
- }, spec.description));
-
-
- var resultItems = results.getItems();
- var messagesDiv = this.createDom('div', { className: 'messages' });
- for (var i = 0; i < resultItems.length; i++) {
- var result = resultItems[i];
-
- if (result.type == 'log') {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
- } else if (result.type == 'expect' && result.passed && !result.passed()) {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
- if (result.trace.stack) {
- messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
- }
- }
- }
-
- if (messagesDiv.childNodes.length > 0) {
- specDiv.appendChild(messagesDiv);
- }
-
- this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
- var console = jasmine.getGlobal().console;
- if (console && console.log) {
- if (console.log.apply) {
- console.log.apply(console, arguments);
- } else {
- console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
- }
- }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
- return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
- var paramMap = {};
- var params = this.getLocation().search.substring(1).split('&');
- for (var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
- }
-
- if (!paramMap.spec) {
- return true;
- }
- return spec.getFullName().indexOf(paramMap.spec) === 0;
-};
+++ /dev/null
-body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
-
-#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
-#HTMLReporter a { text-decoration: none; }
-#HTMLReporter a:hover { text-decoration: underline; }
-#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
-#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
-#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
-#HTMLReporter .version { color: #aaaaaa; }
-#HTMLReporter .banner { margin-top: 14px; }
-#HTMLReporter .duration { color: #aaaaaa; float: right; }
-#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
-#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
-#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
-#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
-#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
-#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
-#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
-#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
-#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
-#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
-#HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
-#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
-#HTMLReporter .runningAlert { background-color: #666666; }
-#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
-#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
-#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
-#HTMLReporter .passingAlert { background-color: #a6b779; }
-#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
-#HTMLReporter .failingAlert { background-color: #cf867e; }
-#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
-#HTMLReporter .results { margin-top: 14px; }
-#HTMLReporter #details { display: none; }
-#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
-#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
-#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
-#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter.showDetails .summary { display: none; }
-#HTMLReporter.showDetails #details { display: block; }
-#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter .summary { margin-top: 14px; }
-#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
-#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
-#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
-#HTMLReporter .description + .suite { margin-top: 0; }
-#HTMLReporter .suite { margin-top: 14px; }
-#HTMLReporter .suite a { color: #333333; }
-#HTMLReporter #details .specDetail { margin-bottom: 28px; }
-#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
-#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
-#HTMLReporter .resultMessage span.result { display: block; }
-#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
-
-#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
-#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
-#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
-#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
-#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
-#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
-#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
-#TrivialReporter .runner.running { background-color: yellow; }
-#TrivialReporter .options { text-align: right; font-size: .8em; }
-#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
-#TrivialReporter .suite .suite { margin: 5px; }
-#TrivialReporter .suite.passed { background-color: #dfd; }
-#TrivialReporter .suite.failed { background-color: #fdd; }
-#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
-#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
-#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
-#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
-#TrivialReporter .spec.skipped { background-color: #bbb; }
-#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
-#TrivialReporter .passed { background-color: #cfc; display: none; }
-#TrivialReporter .failed { background-color: #fbb; }
-#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
-#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
-#TrivialReporter .resultMessage .mismatch { color: black; }
-#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
-#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
-#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
-#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
-#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
+++ /dev/null
-var isCommonJS = typeof window == "undefined" && typeof exports == "object";
-
-/**
- * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
- *
- * @namespace
- */
-var jasmine = {};
-if (isCommonJS) exports.jasmine = jasmine;
-/**
- * @private
- */
-jasmine.unimplementedMethod_ = function() {
- throw new Error("unimplemented method");
-};
-
-/**
- * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
- * a plain old variable and may be redefined by somebody else.
- *
- * @private
- */
-jasmine.undefined = jasmine.___undefined___;
-
-/**
- * Show diagnostic messages in the console if set to true
- *
- */
-jasmine.VERBOSE = false;
-
-/**
- * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
- *
- */
-jasmine.DEFAULT_UPDATE_INTERVAL = 250;
-
-/**
- * Maximum levels of nesting that will be included when an object is pretty-printed
- */
-jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
-
-/**
- * Default timeout interval in milliseconds for waitsFor() blocks.
- */
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
-
-/**
- * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
- * Set to false to let the exception bubble up in the browser.
- *
- */
-jasmine.CATCH_EXCEPTIONS = true;
-
-jasmine.getGlobal = function() {
- function getGlobal() {
- return this;
- }
-
- return getGlobal();
-};
-
-/**
- * Allows for bound functions to be compared. Internal use only.
- *
- * @ignore
- * @private
- * @param base {Object} bound 'this' for the function
- * @param name {Function} function to find
- */
-jasmine.bindOriginal_ = function(base, name) {
- var original = base[name];
- if (original.apply) {
- return function() {
- return original.apply(base, arguments);
- };
- } else {
- // IE support
- return jasmine.getGlobal()[name];
- }
-};
-
-jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
-jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
-jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
-jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
-
-jasmine.MessageResult = function(values) {
- this.type = 'log';
- this.values = values;
- this.trace = new Error(); // todo: test better
-};
-
-jasmine.MessageResult.prototype.toString = function() {
- var text = "";
- for (var i = 0; i < this.values.length; i++) {
- if (i > 0) text += " ";
- if (jasmine.isString_(this.values[i])) {
- text += this.values[i];
- } else {
- text += jasmine.pp(this.values[i]);
- }
- }
- return text;
-};
-
-jasmine.ExpectationResult = function(params) {
- this.type = 'expect';
- this.matcherName = params.matcherName;
- this.passed_ = params.passed;
- this.expected = params.expected;
- this.actual = params.actual;
- this.message = this.passed_ ? 'Passed.' : params.message;
-
- var trace = (params.trace || new Error(this.message));
- this.trace = this.passed_ ? '' : trace;
-};
-
-jasmine.ExpectationResult.prototype.toString = function () {
- return this.message;
-};
-
-jasmine.ExpectationResult.prototype.passed = function () {
- return this.passed_;
-};
-
-/**
- * Getter for the Jasmine environment. Ensures one gets created
- */
-jasmine.getEnv = function() {
- var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
- return env;
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isArray_ = function(value) {
- return jasmine.isA_("Array", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isString_ = function(value) {
- return jasmine.isA_("String", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isNumber_ = function(value) {
- return jasmine.isA_("Number", value);
-};
-
-/**
- * @ignore
- * @private
- * @param {String} typeName
- * @param value
- * @returns {Boolean}
- */
-jasmine.isA_ = function(typeName, value) {
- return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
-};
-
-/**
- * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
- *
- * @param value {Object} an object to be outputted
- * @returns {String}
- */
-jasmine.pp = function(value) {
- var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
- stringPrettyPrinter.format(value);
- return stringPrettyPrinter.string;
-};
-
-/**
- * Returns true if the object is a DOM Node.
- *
- * @param {Object} obj object to check
- * @returns {Boolean}
- */
-jasmine.isDomNode = function(obj) {
- return obj.nodeType > 0;
-};
-
-/**
- * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
- *
- * @example
- * // don't care about which function is passed in, as long as it's a function
- * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
- *
- * @param {Class} clazz
- * @returns matchable object of the type clazz
- */
-jasmine.any = function(clazz) {
- return new jasmine.Matchers.Any(clazz);
-};
-
-/**
- * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
- * attributes on the object.
- *
- * @example
- * // don't care about any other attributes than foo.
- * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
- *
- * @param sample {Object} sample
- * @returns matchable object for the sample
- */
-jasmine.objectContaining = function (sample) {
- return new jasmine.Matchers.ObjectContaining(sample);
-};
-
-/**
- * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
- *
- * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
- * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
- *
- * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
- *
- * Spies are torn down at the end of every spec.
- *
- * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
- *
- * @example
- * // a stub
- * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
- *
- * // spy example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- *
- * // actual foo.not will not be called, execution stops
- * spyOn(foo, 'not');
-
- // foo.not spied upon, execution will continue to implementation
- * spyOn(foo, 'not').andCallThrough();
- *
- * // fake example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- *
- * // foo.not(val) will return val
- * spyOn(foo, 'not').andCallFake(function(value) {return value;});
- *
- * // mock example
- * foo.not(7 == 7);
- * expect(foo.not).toHaveBeenCalled();
- * expect(foo.not).toHaveBeenCalledWith(true);
- *
- * @constructor
- * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
- * @param {String} name
- */
-jasmine.Spy = function(name) {
- /**
- * The name of the spy, if provided.
- */
- this.identity = name || 'unknown';
- /**
- * Is this Object a spy?
- */
- this.isSpy = true;
- /**
- * The actual function this spy stubs.
- */
- this.plan = function() {
- };
- /**
- * Tracking of the most recent call to the spy.
- * @example
- * var mySpy = jasmine.createSpy('foo');
- * mySpy(1, 2);
- * mySpy.mostRecentCall.args = [1, 2];
- */
- this.mostRecentCall = {};
-
- /**
- * Holds arguments for each call to the spy, indexed by call count
- * @example
- * var mySpy = jasmine.createSpy('foo');
- * mySpy(1, 2);
- * mySpy(7, 8);
- * mySpy.mostRecentCall.args = [7, 8];
- * mySpy.argsForCall[0] = [1, 2];
- * mySpy.argsForCall[1] = [7, 8];
- */
- this.argsForCall = [];
- this.calls = [];
-};
-
-/**
- * Tells a spy to call through to the actual implemenatation.
- *
- * @example
- * var foo = {
- * bar: function() { // do some stuff }
- * }
- *
- * // defining a spy on an existing property: foo.bar
- * spyOn(foo, 'bar').andCallThrough();
- */
-jasmine.Spy.prototype.andCallThrough = function() {
- this.plan = this.originalValue;
- return this;
-};
-
-/**
- * For setting the return value of a spy.
- *
- * @example
- * // defining a spy from scratch: foo() returns 'baz'
- * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
- *
- * // defining a spy on an existing property: foo.bar() returns 'baz'
- * spyOn(foo, 'bar').andReturn('baz');
- *
- * @param {Object} value
- */
-jasmine.Spy.prototype.andReturn = function(value) {
- this.plan = function() {
- return value;
- };
- return this;
-};
-
-/**
- * For throwing an exception when a spy is called.
- *
- * @example
- * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
- * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
- *
- * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
- * spyOn(foo, 'bar').andThrow('baz');
- *
- * @param {String} exceptionMsg
- */
-jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
- this.plan = function() {
- throw exceptionMsg;
- };
- return this;
-};
-
-/**
- * Calls an alternate implementation when a spy is called.
- *
- * @example
- * var baz = function() {
- * // do some stuff, return something
- * }
- * // defining a spy from scratch: foo() calls the function baz
- * var foo = jasmine.createSpy('spy on foo').andCall(baz);
- *
- * // defining a spy on an existing property: foo.bar() calls an anonymnous function
- * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
- *
- * @param {Function} fakeFunc
- */
-jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
- this.plan = fakeFunc;
- return this;
-};
-
-/**
- * Resets all of a spy's the tracking variables so that it can be used again.
- *
- * @example
- * spyOn(foo, 'bar');
- *
- * foo.bar();
- *
- * expect(foo.bar.callCount).toEqual(1);
- *
- * foo.bar.reset();
- *
- * expect(foo.bar.callCount).toEqual(0);
- */
-jasmine.Spy.prototype.reset = function() {
- this.wasCalled = false;
- this.callCount = 0;
- this.argsForCall = [];
- this.calls = [];
- this.mostRecentCall = {};
-};
-
-jasmine.createSpy = function(name) {
-
- var spyObj = function() {
- spyObj.wasCalled = true;
- spyObj.callCount++;
- var args = jasmine.util.argsToArray(arguments);
- spyObj.mostRecentCall.object = this;
- spyObj.mostRecentCall.args = args;
- spyObj.argsForCall.push(args);
- spyObj.calls.push({object: this, args: args});
- return spyObj.plan.apply(this, arguments);
- };
-
- var spy = new jasmine.Spy(name);
-
- for (var prop in spy) {
- spyObj[prop] = spy[prop];
- }
-
- spyObj.reset();
-
- return spyObj;
-};
-
-/**
- * Determines whether an object is a spy.
- *
- * @param {jasmine.Spy|Object} putativeSpy
- * @returns {Boolean}
- */
-jasmine.isSpy = function(putativeSpy) {
- return putativeSpy && putativeSpy.isSpy;
-};
-
-/**
- * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
- * large in one call.
- *
- * @param {String} baseName name of spy class
- * @param {Array} methodNames array of names of methods to make spies
- */
-jasmine.createSpyObj = function(baseName, methodNames) {
- if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
- throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
- }
- var obj = {};
- for (var i = 0; i < methodNames.length; i++) {
- obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
- }
- return obj;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.log = function() {
- var spec = jasmine.getEnv().currentSpec;
- spec.log.apply(spec, arguments);
-};
-
-/**
- * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
- *
- * @example
- * // spy example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
- *
- * @see jasmine.createSpy
- * @param obj
- * @param methodName
- * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
- */
-var spyOn = function(obj, methodName) {
- return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
-};
-if (isCommonJS) exports.spyOn = spyOn;
-
-/**
- * Creates a Jasmine spec that will be added to the current suite.
- *
- * // TODO: pending tests
- *
- * @example
- * it('should be true', function() {
- * expect(true).toEqual(true);
- * });
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var it = function(desc, func) {
- return jasmine.getEnv().it(desc, func);
-};
-if (isCommonJS) exports.it = it;
-
-/**
- * Creates a <em>disabled</em> Jasmine spec.
- *
- * A convenience method that allows existing specs to be disabled temporarily during development.
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var xit = function(desc, func) {
- return jasmine.getEnv().xit(desc, func);
-};
-if (isCommonJS) exports.xit = xit;
-
-/**
- * Starts a chain for a Jasmine expectation.
- *
- * It is passed an Object that is the actual value and should chain to one of the many
- * jasmine.Matchers functions.
- *
- * @param {Object} actual Actual value to test against and expected value
- * @return {jasmine.Matchers}
- */
-var expect = function(actual) {
- return jasmine.getEnv().currentSpec.expect(actual);
-};
-if (isCommonJS) exports.expect = expect;
-
-/**
- * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
- *
- * @param {Function} func Function that defines part of a jasmine spec.
- */
-var runs = function(func) {
- jasmine.getEnv().currentSpec.runs(func);
-};
-if (isCommonJS) exports.runs = runs;
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-var waits = function(timeout) {
- jasmine.getEnv().currentSpec.waits(timeout);
-};
-if (isCommonJS) exports.waits = waits;
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
- jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
-};
-if (isCommonJS) exports.waitsFor = waitsFor;
-
-/**
- * A function that is called before each spec in a suite.
- *
- * Used for spec setup, including validating assumptions.
- *
- * @param {Function} beforeEachFunction
- */
-var beforeEach = function(beforeEachFunction) {
- jasmine.getEnv().beforeEach(beforeEachFunction);
-};
-if (isCommonJS) exports.beforeEach = beforeEach;
-
-/**
- * A function that is called after each spec in a suite.
- *
- * Used for restoring any state that is hijacked during spec execution.
- *
- * @param {Function} afterEachFunction
- */
-var afterEach = function(afterEachFunction) {
- jasmine.getEnv().afterEach(afterEachFunction);
-};
-if (isCommonJS) exports.afterEach = afterEach;
-
-/**
- * Defines a suite of specifications.
- *
- * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
- * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
- * of setup in some tests.
- *
- * @example
- * // TODO: a simple suite
- *
- * // TODO: a simple suite with a nested describe block
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var describe = function(description, specDefinitions) {
- return jasmine.getEnv().describe(description, specDefinitions);
-};
-if (isCommonJS) exports.describe = describe;
-
-/**
- * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var xdescribe = function(description, specDefinitions) {
- return jasmine.getEnv().xdescribe(description, specDefinitions);
-};
-if (isCommonJS) exports.xdescribe = xdescribe;
-
-
-// Provide the XMLHttpRequest class for IE 5.x-6.x:
-jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
- function tryIt(f) {
- try {
- return f();
- } catch(e) {
- }
- return null;
- }
-
- var xhr = tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP.6.0");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP.3.0");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Microsoft.XMLHTTP");
- });
-
- if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
-
- return xhr;
-} : XMLHttpRequest;
-/**
- * @namespace
- */
-jasmine.util = {};
-
-/**
- * Declare that a child class inherit it's prototype from the parent class.
- *
- * @private
- * @param {Function} childClass
- * @param {Function} parentClass
- */
-jasmine.util.inherit = function(childClass, parentClass) {
- /**
- * @private
- */
- var subclass = function() {
- };
- subclass.prototype = parentClass.prototype;
- childClass.prototype = new subclass();
-};
-
-jasmine.util.formatException = function(e) {
- var lineNumber;
- if (e.line) {
- lineNumber = e.line;
- }
- else if (e.lineNumber) {
- lineNumber = e.lineNumber;
- }
-
- var file;
-
- if (e.sourceURL) {
- file = e.sourceURL;
- }
- else if (e.fileName) {
- file = e.fileName;
- }
-
- var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
-
- if (file && lineNumber) {
- message += ' in ' + file + ' (line ' + lineNumber + ')';
- }
-
- return message;
-};
-
-jasmine.util.htmlEscape = function(str) {
- if (!str) return str;
- return str.replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>');
-};
-
-jasmine.util.argsToArray = function(args) {
- var arrayOfArgs = [];
- for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
- return arrayOfArgs;
-};
-
-jasmine.util.extend = function(destination, source) {
- for (var property in source) destination[property] = source[property];
- return destination;
-};
-
-/**
- * Environment for Jasmine
- *
- * @constructor
- */
-jasmine.Env = function() {
- this.currentSpec = null;
- this.currentSuite = null;
- this.currentRunner_ = new jasmine.Runner(this);
-
- this.reporter = new jasmine.MultiReporter();
-
- this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
- this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
- this.lastUpdate = 0;
- this.specFilter = function() {
- return true;
- };
-
- this.nextSpecId_ = 0;
- this.nextSuiteId_ = 0;
- this.equalityTesters_ = [];
-
- // wrap matchers
- this.matchersClass = function() {
- jasmine.Matchers.apply(this, arguments);
- };
- jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
-
- jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
-};
-
-
-jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
-jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
-jasmine.Env.prototype.setInterval = jasmine.setInterval;
-jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
-
-/**
- * @returns an object containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.version = function () {
- if (jasmine.version_) {
- return jasmine.version_;
- } else {
- throw new Error('Version not set');
- }
-};
-
-/**
- * @returns string containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.versionString = function() {
- if (!jasmine.version_) {
- return "version unknown";
- }
-
- var version = this.version();
- var versionString = version.major + "." + version.minor + "." + version.build;
- if (version.release_candidate) {
- versionString += ".rc" + version.release_candidate;
- }
- versionString += " revision " + version.revision;
- return versionString;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSpecId = function () {
- return this.nextSpecId_++;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSuiteId = function () {
- return this.nextSuiteId_++;
-};
-
-/**
- * Register a reporter to receive status updates from Jasmine.
- * @param {jasmine.Reporter} reporter An object which will receive status updates.
- */
-jasmine.Env.prototype.addReporter = function(reporter) {
- this.reporter.addReporter(reporter);
-};
-
-jasmine.Env.prototype.execute = function() {
- this.currentRunner_.execute();
-};
-
-jasmine.Env.prototype.describe = function(description, specDefinitions) {
- var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
-
- var parentSuite = this.currentSuite;
- if (parentSuite) {
- parentSuite.add(suite);
- } else {
- this.currentRunner_.add(suite);
- }
-
- this.currentSuite = suite;
-
- var declarationError = null;
- try {
- specDefinitions.call(suite);
- } catch(e) {
- declarationError = e;
- }
-
- if (declarationError) {
- this.it("encountered a declaration exception", function() {
- throw declarationError;
- });
- }
-
- this.currentSuite = parentSuite;
-
- return suite;
-};
-
-jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
- if (this.currentSuite) {
- this.currentSuite.beforeEach(beforeEachFunction);
- } else {
- this.currentRunner_.beforeEach(beforeEachFunction);
- }
-};
-
-jasmine.Env.prototype.currentRunner = function () {
- return this.currentRunner_;
-};
-
-jasmine.Env.prototype.afterEach = function(afterEachFunction) {
- if (this.currentSuite) {
- this.currentSuite.afterEach(afterEachFunction);
- } else {
- this.currentRunner_.afterEach(afterEachFunction);
- }
-
-};
-
-jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
- return {
- execute: function() {
- }
- };
-};
-
-jasmine.Env.prototype.it = function(description, func) {
- var spec = new jasmine.Spec(this, this.currentSuite, description);
- this.currentSuite.add(spec);
- this.currentSpec = spec;
-
- if (func) {
- spec.runs(func);
- }
-
- return spec;
-};
-
-jasmine.Env.prototype.xit = function(desc, func) {
- return {
- id: this.nextSpecId(),
- runs: function() {
- }
- };
-};
-
-jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
- if (a.source != b.source)
- mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
-
- if (a.ignoreCase != b.ignoreCase)
- mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
-
- if (a.global != b.global)
- mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
-
- if (a.multiline != b.multiline)
- mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
-
- if (a.sticky != b.sticky)
- mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
-
- return (mismatchValues.length === 0);
-};
-
-jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
- if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
- return true;
- }
-
- a.__Jasmine_been_here_before__ = b;
- b.__Jasmine_been_here_before__ = a;
-
- var hasKey = function(obj, keyName) {
- return obj !== null && obj[keyName] !== jasmine.undefined;
- };
-
- for (var property in b) {
- if (!hasKey(a, property) && hasKey(b, property)) {
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
- }
- }
- for (property in a) {
- if (!hasKey(b, property) && hasKey(a, property)) {
- mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
- }
- }
- for (property in b) {
- if (property == '__Jasmine_been_here_before__') continue;
- if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
- mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
- }
- }
-
- if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
- mismatchValues.push("arrays were not the same length");
- }
-
- delete a.__Jasmine_been_here_before__;
- delete b.__Jasmine_been_here_before__;
- return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
- mismatchKeys = mismatchKeys || [];
- mismatchValues = mismatchValues || [];
-
- for (var i = 0; i < this.equalityTesters_.length; i++) {
- var equalityTester = this.equalityTesters_[i];
- var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
- if (result !== jasmine.undefined) return result;
- }
-
- if (a === b) return true;
-
- if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
- return (a == jasmine.undefined && b == jasmine.undefined);
- }
-
- if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
- return a === b;
- }
-
- if (a instanceof Date && b instanceof Date) {
- return a.getTime() == b.getTime();
- }
-
- if (a.jasmineMatches) {
- return a.jasmineMatches(b);
- }
-
- if (b.jasmineMatches) {
- return b.jasmineMatches(a);
- }
-
- if (a instanceof jasmine.Matchers.ObjectContaining) {
- return a.matches(b);
- }
-
- if (b instanceof jasmine.Matchers.ObjectContaining) {
- return b.matches(a);
- }
-
- if (jasmine.isString_(a) && jasmine.isString_(b)) {
- return (a == b);
- }
-
- if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
- return (a == b);
- }
-
- if (a instanceof RegExp && b instanceof RegExp) {
- return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
- }
-
- if (typeof a === "object" && typeof b === "object") {
- return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
- }
-
- //Straight check
- return (a === b);
-};
-
-jasmine.Env.prototype.contains_ = function(haystack, needle) {
- if (jasmine.isArray_(haystack)) {
- for (var i = 0; i < haystack.length; i++) {
- if (this.equals_(haystack[i], needle)) return true;
- }
- return false;
- }
- return haystack.indexOf(needle) >= 0;
-};
-
-jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
- this.equalityTesters_.push(equalityTester);
-};
-/** No-op base class for Jasmine reporters.
- *
- * @constructor
- */
-jasmine.Reporter = function() {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecResults = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.log = function(str) {
-};
-
-/**
- * Blocks are functions with executable code that make up a spec.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {Function} func
- * @param {jasmine.Spec} spec
- */
-jasmine.Block = function(env, func, spec) {
- this.env = env;
- this.func = func;
- this.spec = spec;
-};
-
-jasmine.Block.prototype.execute = function(onComplete) {
- if (!jasmine.CATCH_EXCEPTIONS) {
- this.func.apply(this.spec);
- }
- else {
- try {
- this.func.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
- }
- }
- onComplete();
-};
-/** JavaScript API reporter.
- *
- * @constructor
- */
-jasmine.JsApiReporter = function() {
- this.started = false;
- this.finished = false;
- this.suites_ = [];
- this.results_ = {};
-};
-
-jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
- this.started = true;
- var suites = runner.topLevelSuites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- this.suites_.push(this.summarize_(suite));
- }
-};
-
-jasmine.JsApiReporter.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
- var isSuite = suiteOrSpec instanceof jasmine.Suite;
- var summary = {
- id: suiteOrSpec.id,
- name: suiteOrSpec.description,
- type: isSuite ? 'suite' : 'spec',
- children: []
- };
-
- if (isSuite) {
- var children = suiteOrSpec.children();
- for (var i = 0; i < children.length; i++) {
- summary.children.push(this.summarize_(children[i]));
- }
- }
- return summary;
-};
-
-jasmine.JsApiReporter.prototype.results = function() {
- return this.results_;
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
- return this.results_[specId];
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
- this.finished = true;
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
- this.results_[spec.id] = {
- messages: spec.results().getItems(),
- result: spec.results().failedCount > 0 ? "failed" : "passed"
- };
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.log = function(str) {
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
- var results = {};
- for (var i = 0; i < specIds.length; i++) {
- var specId = specIds[i];
- results[specId] = this.summarizeResult_(this.results_[specId]);
- }
- return results;
-};
-
-jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
- var summaryMessages = [];
- var messagesLength = result.messages.length;
- for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
- var resultMessage = result.messages[messageIndex];
- summaryMessages.push({
- text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
- passed: resultMessage.passed ? resultMessage.passed() : true,
- type: resultMessage.type,
- message: resultMessage.message,
- trace: {
- stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
- }
- });
- }
-
- return {
- result : result.result,
- messages : summaryMessages
- };
-};
-
-/**
- * @constructor
- * @param {jasmine.Env} env
- * @param actual
- * @param {jasmine.Spec} spec
- */
-jasmine.Matchers = function(env, actual, spec, opt_isNot) {
- this.env = env;
- this.actual = actual;
- this.spec = spec;
- this.isNot = opt_isNot || false;
- this.reportWasCalled_ = false;
-};
-
-// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
-jasmine.Matchers.pp = function(str) {
- throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
-};
-
-// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
-jasmine.Matchers.prototype.report = function(result, failing_message, details) {
- throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
-};
-
-jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
- for (var methodName in prototype) {
- if (methodName == 'report') continue;
- var orig = prototype[methodName];
- matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
- }
-};
-
-jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
- return function() {
- var matcherArgs = jasmine.util.argsToArray(arguments);
- var result = matcherFunction.apply(this, arguments);
-
- if (this.isNot) {
- result = !result;
- }
-
- if (this.reportWasCalled_) return result;
-
- var message;
- if (!result) {
- if (this.message) {
- message = this.message.apply(this, arguments);
- if (jasmine.isArray_(message)) {
- message = message[this.isNot ? 1 : 0];
- }
- } else {
- var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
- message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
- if (matcherArgs.length > 0) {
- for (var i = 0; i < matcherArgs.length; i++) {
- if (i > 0) message += ",";
- message += " " + jasmine.pp(matcherArgs[i]);
- }
- }
- message += ".";
- }
- }
- var expectationResult = new jasmine.ExpectationResult({
- matcherName: matcherName,
- passed: result,
- expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
- actual: this.actual,
- message: message
- });
- this.spec.addMatcherResult(expectationResult);
- return jasmine.undefined;
- };
-};
-
-
-
-
-/**
- * toBe: compares the actual to the expected using ===
- * @param expected
- */
-jasmine.Matchers.prototype.toBe = function(expected) {
- return this.actual === expected;
-};
-
-/**
- * toNotBe: compares the actual to the expected using !==
- * @param expected
- * @deprecated as of 1.0. Use not.toBe() instead.
- */
-jasmine.Matchers.prototype.toNotBe = function(expected) {
- return this.actual !== expected;
-};
-
-/**
- * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toEqual = function(expected) {
- return this.env.equals_(this.actual, expected);
-};
-
-/**
- * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
- * @param expected
- * @deprecated as of 1.0. Use not.toEqual() instead.
- */
-jasmine.Matchers.prototype.toNotEqual = function(expected) {
- return !this.env.equals_(this.actual, expected);
-};
-
-/**
- * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
- * a pattern or a String.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toMatch = function(expected) {
- return new RegExp(expected).test(this.actual);
-};
-
-/**
- * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
- * @param expected
- * @deprecated as of 1.0. Use not.toMatch() instead.
- */
-jasmine.Matchers.prototype.toNotMatch = function(expected) {
- return !(new RegExp(expected).test(this.actual));
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeDefined = function() {
- return (this.actual !== jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeUndefined = function() {
- return (this.actual === jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to null.
- */
-jasmine.Matchers.prototype.toBeNull = function() {
- return (this.actual === null);
-};
-
-/**
- * Matcher that compares the actual to NaN.
- */
-jasmine.Matchers.prototype.toBeNaN = function() {
- this.message = function() {
- return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
- };
-
- return (this.actual !== this.actual);
-};
-
-/**
- * Matcher that boolean not-nots the actual.
- */
-jasmine.Matchers.prototype.toBeTruthy = function() {
- return !!this.actual;
-};
-
-
-/**
- * Matcher that boolean nots the actual.
- */
-jasmine.Matchers.prototype.toBeFalsy = function() {
- return !this.actual;
-};
-
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called.
- */
-jasmine.Matchers.prototype.toHaveBeenCalled = function() {
- if (arguments.length > 0) {
- throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy " + this.actual.identity + " to have been called.",
- "Expected spy " + this.actual.identity + " not to have been called."
- ];
- };
-
- return this.actual.wasCalled;
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
-jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was not called.
- *
- * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
- */
-jasmine.Matchers.prototype.wasNotCalled = function() {
- if (arguments.length > 0) {
- throw new Error('wasNotCalled does not take arguments');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy " + this.actual.identity + " to not have been called.",
- "Expected spy " + this.actual.identity + " to have been called."
- ];
- };
-
- return !this.actual.wasCalled;
-};
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
- *
- * @example
- *
- */
-jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
- this.message = function() {
- var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
- var positiveMessage = "";
- if (this.actual.callCount === 0) {
- positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
- } else {
- positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
- }
- return [positiveMessage, invertedMessage];
- };
-
- return this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
-
-/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasNotCalledWith = function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
- "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
- ];
- };
-
- return !this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/**
- * Matcher that checks that the expected item is an element in the actual Array.
- *
- * @param {Object} expected
- */
-jasmine.Matchers.prototype.toContain = function(expected) {
- return this.env.contains_(this.actual, expected);
-};
-
-/**
- * Matcher that checks that the expected item is NOT an element in the actual Array.
- *
- * @param {Object} expected
- * @deprecated as of 1.0. Use not.toContain() instead.
- */
-jasmine.Matchers.prototype.toNotContain = function(expected) {
- return !this.env.contains_(this.actual, expected);
-};
-
-jasmine.Matchers.prototype.toBeLessThan = function(expected) {
- return this.actual < expected;
-};
-
-jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
- return this.actual > expected;
-};
-
-/**
- * Matcher that checks that the expected item is equal to the actual item
- * up to a given level of decimal precision (default 2).
- *
- * @param {Number} expected
- * @param {Number} precision, as number of decimal places
- */
-jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
- if (!(precision === 0)) {
- precision = precision || 2;
- }
- return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
-};
-
-/**
- * Matcher that checks that the expected exception was thrown by the actual.
- *
- * @param {String} [expected]
- */
-jasmine.Matchers.prototype.toThrow = function(expected) {
- var result = false;
- var exception;
- if (typeof this.actual != 'function') {
- throw new Error('Actual is not a function');
- }
- try {
- this.actual();
- } catch (e) {
- exception = e;
- }
- if (exception) {
- result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
- }
-
- var not = this.isNot ? "not " : "";
-
- this.message = function() {
- if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
- return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
- } else {
- return "Expected function to throw an exception.";
- }
- };
-
- return result;
-};
-
-jasmine.Matchers.Any = function(expectedClass) {
- this.expectedClass = expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
- if (this.expectedClass == String) {
- return typeof other == 'string' || other instanceof String;
- }
-
- if (this.expectedClass == Number) {
- return typeof other == 'number' || other instanceof Number;
- }
-
- if (this.expectedClass == Function) {
- return typeof other == 'function' || other instanceof Function;
- }
-
- if (this.expectedClass == Object) {
- return typeof other == 'object';
- }
-
- return other instanceof this.expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineToString = function() {
- return '<jasmine.any(' + this.expectedClass + ')>';
-};
-
-jasmine.Matchers.ObjectContaining = function (sample) {
- this.sample = sample;
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
- mismatchKeys = mismatchKeys || [];
- mismatchValues = mismatchValues || [];
-
- var env = jasmine.getEnv();
-
- var hasKey = function(obj, keyName) {
- return obj != null && obj[keyName] !== jasmine.undefined;
- };
-
- for (var property in this.sample) {
- if (!hasKey(other, property) && hasKey(this.sample, property)) {
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
- }
- else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
- mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
- }
- }
-
- return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
- return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
-};
-// Mock setTimeout, clearTimeout
-// Contributed by Pivotal Computer Systems, www.pivotalsf.com
-
-jasmine.FakeTimer = function() {
- this.reset();
-
- var self = this;
- self.setTimeout = function(funcToCall, millis) {
- self.timeoutsMade++;
- self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
- return self.timeoutsMade;
- };
-
- self.setInterval = function(funcToCall, millis) {
- self.timeoutsMade++;
- self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
- return self.timeoutsMade;
- };
-
- self.clearTimeout = function(timeoutKey) {
- self.scheduledFunctions[timeoutKey] = jasmine.undefined;
- };
-
- self.clearInterval = function(timeoutKey) {
- self.scheduledFunctions[timeoutKey] = jasmine.undefined;
- };
-
-};
-
-jasmine.FakeTimer.prototype.reset = function() {
- this.timeoutsMade = 0;
- this.scheduledFunctions = {};
- this.nowMillis = 0;
-};
-
-jasmine.FakeTimer.prototype.tick = function(millis) {
- var oldMillis = this.nowMillis;
- var newMillis = oldMillis + millis;
- this.runFunctionsWithinRange(oldMillis, newMillis);
- this.nowMillis = newMillis;
-};
-
-jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
- var scheduledFunc;
- var funcsToRun = [];
- for (var timeoutKey in this.scheduledFunctions) {
- scheduledFunc = this.scheduledFunctions[timeoutKey];
- if (scheduledFunc != jasmine.undefined &&
- scheduledFunc.runAtMillis >= oldMillis &&
- scheduledFunc.runAtMillis <= nowMillis) {
- funcsToRun.push(scheduledFunc);
- this.scheduledFunctions[timeoutKey] = jasmine.undefined;
- }
- }
-
- if (funcsToRun.length > 0) {
- funcsToRun.sort(function(a, b) {
- return a.runAtMillis - b.runAtMillis;
- });
- for (var i = 0; i < funcsToRun.length; ++i) {
- try {
- var funcToRun = funcsToRun[i];
- this.nowMillis = funcToRun.runAtMillis;
- funcToRun.funcToCall();
- if (funcToRun.recurring) {
- this.scheduleFunction(funcToRun.timeoutKey,
- funcToRun.funcToCall,
- funcToRun.millis,
- true);
- }
- } catch(e) {
- }
- }
- this.runFunctionsWithinRange(oldMillis, nowMillis);
- }
-};
-
-jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
- this.scheduledFunctions[timeoutKey] = {
- runAtMillis: this.nowMillis + millis,
- funcToCall: funcToCall,
- recurring: recurring,
- timeoutKey: timeoutKey,
- millis: millis
- };
-};
-
-/**
- * @namespace
- */
-jasmine.Clock = {
- defaultFakeTimer: new jasmine.FakeTimer(),
-
- reset: function() {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.defaultFakeTimer.reset();
- },
-
- tick: function(millis) {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.defaultFakeTimer.tick(millis);
- },
-
- runFunctionsWithinRange: function(oldMillis, nowMillis) {
- jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
- },
-
- scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
- jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
- },
-
- useMock: function() {
- if (!jasmine.Clock.isInstalled()) {
- var spec = jasmine.getEnv().currentSpec;
- spec.after(jasmine.Clock.uninstallMock);
-
- jasmine.Clock.installMock();
- }
- },
-
- installMock: function() {
- jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
- },
-
- uninstallMock: function() {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.installed = jasmine.Clock.real;
- },
-
- real: {
- setTimeout: jasmine.getGlobal().setTimeout,
- clearTimeout: jasmine.getGlobal().clearTimeout,
- setInterval: jasmine.getGlobal().setInterval,
- clearInterval: jasmine.getGlobal().clearInterval
- },
-
- assertInstalled: function() {
- if (!jasmine.Clock.isInstalled()) {
- throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
- }
- },
-
- isInstalled: function() {
- return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
- },
-
- installed: null
-};
-jasmine.Clock.installed = jasmine.Clock.real;
-
-//else for IE support
-jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
- if (jasmine.Clock.installed.setTimeout.apply) {
- return jasmine.Clock.installed.setTimeout.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.setTimeout(funcToCall, millis);
- }
-};
-
-jasmine.getGlobal().setInterval = function(funcToCall, millis) {
- if (jasmine.Clock.installed.setInterval.apply) {
- return jasmine.Clock.installed.setInterval.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.setInterval(funcToCall, millis);
- }
-};
-
-jasmine.getGlobal().clearTimeout = function(timeoutKey) {
- if (jasmine.Clock.installed.clearTimeout.apply) {
- return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.clearTimeout(timeoutKey);
- }
-};
-
-jasmine.getGlobal().clearInterval = function(timeoutKey) {
- if (jasmine.Clock.installed.clearTimeout.apply) {
- return jasmine.Clock.installed.clearInterval.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.clearInterval(timeoutKey);
- }
-};
-
-/**
- * @constructor
- */
-jasmine.MultiReporter = function() {
- this.subReporters_ = [];
-};
-jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
-
-jasmine.MultiReporter.prototype.addReporter = function(reporter) {
- this.subReporters_.push(reporter);
-};
-
-(function() {
- var functionNames = [
- "reportRunnerStarting",
- "reportRunnerResults",
- "reportSuiteResults",
- "reportSpecStarting",
- "reportSpecResults",
- "log"
- ];
- for (var i = 0; i < functionNames.length; i++) {
- var functionName = functionNames[i];
- jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
- return function() {
- for (var j = 0; j < this.subReporters_.length; j++) {
- var subReporter = this.subReporters_[j];
- if (subReporter[functionName]) {
- subReporter[functionName].apply(subReporter, arguments);
- }
- }
- };
- })(functionName);
- }
-})();
-/**
- * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
- *
- * @constructor
- */
-jasmine.NestedResults = function() {
- /**
- * The total count of results
- */
- this.totalCount = 0;
- /**
- * Number of passed results
- */
- this.passedCount = 0;
- /**
- * Number of failed results
- */
- this.failedCount = 0;
- /**
- * Was this suite/spec skipped?
- */
- this.skipped = false;
- /**
- * @ignore
- */
- this.items_ = [];
-};
-
-/**
- * Roll up the result counts.
- *
- * @param result
- */
-jasmine.NestedResults.prototype.rollupCounts = function(result) {
- this.totalCount += result.totalCount;
- this.passedCount += result.passedCount;
- this.failedCount += result.failedCount;
-};
-
-/**
- * Adds a log message.
- * @param values Array of message parts which will be concatenated later.
- */
-jasmine.NestedResults.prototype.log = function(values) {
- this.items_.push(new jasmine.MessageResult(values));
-};
-
-/**
- * Getter for the results: message & results.
- */
-jasmine.NestedResults.prototype.getItems = function() {
- return this.items_;
-};
-
-/**
- * Adds a result, tracking counts (total, passed, & failed)
- * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
- */
-jasmine.NestedResults.prototype.addResult = function(result) {
- if (result.type != 'log') {
- if (result.items_) {
- this.rollupCounts(result);
- } else {
- this.totalCount++;
- if (result.passed()) {
- this.passedCount++;
- } else {
- this.failedCount++;
- }
- }
- }
- this.items_.push(result);
-};
-
-/**
- * @returns {Boolean} True if <b>everything</b> below passed
- */
-jasmine.NestedResults.prototype.passed = function() {
- return this.passedCount === this.totalCount;
-};
-/**
- * Base class for pretty printing for expectation results.
- */
-jasmine.PrettyPrinter = function() {
- this.ppNestLevel_ = 0;
-};
-
-/**
- * Formats a value in a nice, human-readable string.
- *
- * @param value
- */
-jasmine.PrettyPrinter.prototype.format = function(value) {
- this.ppNestLevel_++;
- try {
- if (value === jasmine.undefined) {
- this.emitScalar('undefined');
- } else if (value === null) {
- this.emitScalar('null');
- } else if (value === jasmine.getGlobal()) {
- this.emitScalar('<global>');
- } else if (value.jasmineToString) {
- this.emitScalar(value.jasmineToString());
- } else if (typeof value === 'string') {
- this.emitString(value);
- } else if (jasmine.isSpy(value)) {
- this.emitScalar("spy on " + value.identity);
- } else if (value instanceof RegExp) {
- this.emitScalar(value.toString());
- } else if (typeof value === 'function') {
- this.emitScalar('Function');
- } else if (typeof value.nodeType === 'number') {
- this.emitScalar('HTMLNode');
- } else if (value instanceof Date) {
- this.emitScalar('Date(' + value + ')');
- } else if (value.__Jasmine_been_here_before__) {
- this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
- } else if (jasmine.isArray_(value) || typeof value == 'object') {
- value.__Jasmine_been_here_before__ = true;
- if (jasmine.isArray_(value)) {
- this.emitArray(value);
- } else {
- this.emitObject(value);
- }
- delete value.__Jasmine_been_here_before__;
- } else {
- this.emitScalar(value.toString());
- }
- } finally {
- this.ppNestLevel_--;
- }
-};
-
-jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
- for (var property in obj) {
- if (!obj.hasOwnProperty(property)) continue;
- if (property == '__Jasmine_been_here_before__') continue;
- fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
- obj.__lookupGetter__(property) !== null) : false);
- }
-};
-
-jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
-
-jasmine.StringPrettyPrinter = function() {
- jasmine.PrettyPrinter.call(this);
-
- this.string = '';
-};
-jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
-
-jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
- this.append(value);
-};
-
-jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
- this.append("'" + value + "'");
-};
-
-jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
- if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
- this.append("Array");
- return;
- }
-
- this.append('[ ');
- for (var i = 0; i < array.length; i++) {
- if (i > 0) {
- this.append(', ');
- }
- this.format(array[i]);
- }
- this.append(' ]');
-};
-
-jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
- if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
- this.append("Object");
- return;
- }
-
- var self = this;
- this.append('{ ');
- var first = true;
-
- this.iterateObject(obj, function(property, isGetter) {
- if (first) {
- first = false;
- } else {
- self.append(', ');
- }
-
- self.append(property);
- self.append(' : ');
- if (isGetter) {
- self.append('<getter>');
- } else {
- self.format(obj[property]);
- }
- });
-
- this.append(' }');
-};
-
-jasmine.StringPrettyPrinter.prototype.append = function(value) {
- this.string += value;
-};
-jasmine.Queue = function(env) {
- this.env = env;
-
- // parallel to blocks. each true value in this array means the block will
- // get executed even if we abort
- this.ensured = [];
- this.blocks = [];
- this.running = false;
- this.index = 0;
- this.offset = 0;
- this.abort = false;
-};
-
-jasmine.Queue.prototype.addBefore = function(block, ensure) {
- if (ensure === jasmine.undefined) {
- ensure = false;
- }
-
- this.blocks.unshift(block);
- this.ensured.unshift(ensure);
-};
-
-jasmine.Queue.prototype.add = function(block, ensure) {
- if (ensure === jasmine.undefined) {
- ensure = false;
- }
-
- this.blocks.push(block);
- this.ensured.push(ensure);
-};
-
-jasmine.Queue.prototype.insertNext = function(block, ensure) {
- if (ensure === jasmine.undefined) {
- ensure = false;
- }
-
- this.ensured.splice((this.index + this.offset + 1), 0, ensure);
- this.blocks.splice((this.index + this.offset + 1), 0, block);
- this.offset++;
-};
-
-jasmine.Queue.prototype.start = function(onComplete) {
- this.running = true;
- this.onComplete = onComplete;
- this.next_();
-};
-
-jasmine.Queue.prototype.isRunning = function() {
- return this.running;
-};
-
-jasmine.Queue.LOOP_DONT_RECURSE = true;
-
-jasmine.Queue.prototype.next_ = function() {
- var self = this;
- var goAgain = true;
-
- while (goAgain) {
- goAgain = false;
-
- if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
- var calledSynchronously = true;
- var completedSynchronously = false;
-
- var onComplete = function () {
- if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
- completedSynchronously = true;
- return;
- }
-
- if (self.blocks[self.index].abort) {
- self.abort = true;
- }
-
- self.offset = 0;
- self.index++;
-
- var now = new Date().getTime();
- if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
- self.env.lastUpdate = now;
- self.env.setTimeout(function() {
- self.next_();
- }, 0);
- } else {
- if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
- goAgain = true;
- } else {
- self.next_();
- }
- }
- };
- self.blocks[self.index].execute(onComplete);
-
- calledSynchronously = false;
- if (completedSynchronously) {
- onComplete();
- }
-
- } else {
- self.running = false;
- if (self.onComplete) {
- self.onComplete();
- }
- }
- }
-};
-
-jasmine.Queue.prototype.results = function() {
- var results = new jasmine.NestedResults();
- for (var i = 0; i < this.blocks.length; i++) {
- if (this.blocks[i].results) {
- results.addResult(this.blocks[i].results());
- }
- }
- return results;
-};
-
-
-/**
- * Runner
- *
- * @constructor
- * @param {jasmine.Env} env
- */
-jasmine.Runner = function(env) {
- var self = this;
- self.env = env;
- self.queue = new jasmine.Queue(env);
- self.before_ = [];
- self.after_ = [];
- self.suites_ = [];
-};
-
-jasmine.Runner.prototype.execute = function() {
- var self = this;
- if (self.env.reporter.reportRunnerStarting) {
- self.env.reporter.reportRunnerStarting(this);
- }
- self.queue.start(function () {
- self.finishCallback();
- });
-};
-
-jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
- beforeEachFunction.typeName = 'beforeEach';
- this.before_.splice(0,0,beforeEachFunction);
-};
-
-jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
- afterEachFunction.typeName = 'afterEach';
- this.after_.splice(0,0,afterEachFunction);
-};
-
-
-jasmine.Runner.prototype.finishCallback = function() {
- this.env.reporter.reportRunnerResults(this);
-};
-
-jasmine.Runner.prototype.addSuite = function(suite) {
- this.suites_.push(suite);
-};
-
-jasmine.Runner.prototype.add = function(block) {
- if (block instanceof jasmine.Suite) {
- this.addSuite(block);
- }
- this.queue.add(block);
-};
-
-jasmine.Runner.prototype.specs = function () {
- var suites = this.suites();
- var specs = [];
- for (var i = 0; i < suites.length; i++) {
- specs = specs.concat(suites[i].specs());
- }
- return specs;
-};
-
-jasmine.Runner.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.Runner.prototype.topLevelSuites = function() {
- var topLevelSuites = [];
- for (var i = 0; i < this.suites_.length; i++) {
- if (!this.suites_[i].parentSuite) {
- topLevelSuites.push(this.suites_[i]);
- }
- }
- return topLevelSuites;
-};
-
-jasmine.Runner.prototype.results = function() {
- return this.queue.results();
-};
-/**
- * Internal representation of a Jasmine specification, or test.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {jasmine.Suite} suite
- * @param {String} description
- */
-jasmine.Spec = function(env, suite, description) {
- if (!env) {
- throw new Error('jasmine.Env() required');
- }
- if (!suite) {
- throw new Error('jasmine.Suite() required');
- }
- var spec = this;
- spec.id = env.nextSpecId ? env.nextSpecId() : null;
- spec.env = env;
- spec.suite = suite;
- spec.description = description;
- spec.queue = new jasmine.Queue(env);
-
- spec.afterCallbacks = [];
- spec.spies_ = [];
-
- spec.results_ = new jasmine.NestedResults();
- spec.results_.description = description;
- spec.matchersClass = null;
-};
-
-jasmine.Spec.prototype.getFullName = function() {
- return this.suite.getFullName() + ' ' + this.description + '.';
-};
-
-
-jasmine.Spec.prototype.results = function() {
- return this.results_;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.Spec.prototype.log = function() {
- return this.results_.log(arguments);
-};
-
-jasmine.Spec.prototype.runs = function (func) {
- var block = new jasmine.Block(this.env, func, this);
- this.addToQueue(block);
- return this;
-};
-
-jasmine.Spec.prototype.addToQueue = function (block) {
- if (this.queue.isRunning()) {
- this.queue.insertNext(block);
- } else {
- this.queue.add(block);
- }
-};
-
-/**
- * @param {jasmine.ExpectationResult} result
- */
-jasmine.Spec.prototype.addMatcherResult = function(result) {
- this.results_.addResult(result);
-};
-
-jasmine.Spec.prototype.expect = function(actual) {
- var positive = new (this.getMatchersClass_())(this.env, actual, this);
- positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
- return positive;
-};
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-jasmine.Spec.prototype.waits = function(timeout) {
- var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
- this.addToQueue(waitsFunc);
- return this;
-};
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
- var latchFunction_ = null;
- var optional_timeoutMessage_ = null;
- var optional_timeout_ = null;
-
- for (var i = 0; i < arguments.length; i++) {
- var arg = arguments[i];
- switch (typeof arg) {
- case 'function':
- latchFunction_ = arg;
- break;
- case 'string':
- optional_timeoutMessage_ = arg;
- break;
- case 'number':
- optional_timeout_ = arg;
- break;
- }
- }
-
- var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
- this.addToQueue(waitsForFunc);
- return this;
-};
-
-jasmine.Spec.prototype.fail = function (e) {
- var expectationResult = new jasmine.ExpectationResult({
- passed: false,
- message: e ? jasmine.util.formatException(e) : 'Exception',
- trace: { stack: e.stack }
- });
- this.results_.addResult(expectationResult);
-};
-
-jasmine.Spec.prototype.getMatchersClass_ = function() {
- return this.matchersClass || this.env.matchersClass;
-};
-
-jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
- var parent = this.getMatchersClass_();
- var newMatchersClass = function() {
- parent.apply(this, arguments);
- };
- jasmine.util.inherit(newMatchersClass, parent);
- jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
- this.matchersClass = newMatchersClass;
-};
-
-jasmine.Spec.prototype.finishCallback = function() {
- this.env.reporter.reportSpecResults(this);
-};
-
-jasmine.Spec.prototype.finish = function(onComplete) {
- this.removeAllSpies();
- this.finishCallback();
- if (onComplete) {
- onComplete();
- }
-};
-
-jasmine.Spec.prototype.after = function(doAfter) {
- if (this.queue.isRunning()) {
- this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
- } else {
- this.afterCallbacks.unshift(doAfter);
- }
-};
-
-jasmine.Spec.prototype.execute = function(onComplete) {
- var spec = this;
- if (!spec.env.specFilter(spec)) {
- spec.results_.skipped = true;
- spec.finish(onComplete);
- return;
- }
-
- this.env.reporter.reportSpecStarting(this);
-
- spec.env.currentSpec = spec;
-
- spec.addBeforesAndAftersToQueue();
-
- spec.queue.start(function () {
- spec.finish(onComplete);
- });
-};
-
-jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
- var runner = this.env.currentRunner();
- var i;
-
- for (var suite = this.suite; suite; suite = suite.parentSuite) {
- for (i = 0; i < suite.before_.length; i++) {
- this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
- }
- }
- for (i = 0; i < runner.before_.length; i++) {
- this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
- }
- for (i = 0; i < this.afterCallbacks.length; i++) {
- this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
- }
- for (suite = this.suite; suite; suite = suite.parentSuite) {
- for (i = 0; i < suite.after_.length; i++) {
- this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
- }
- }
- for (i = 0; i < runner.after_.length; i++) {
- this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
- }
-};
-
-jasmine.Spec.prototype.explodes = function() {
- throw 'explodes function should not have been called';
-};
-
-jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
- if (obj == jasmine.undefined) {
- throw "spyOn could not find an object to spy upon for " + methodName + "()";
- }
-
- if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
- throw methodName + '() method does not exist';
- }
-
- if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
- throw new Error(methodName + ' has already been spied upon');
- }
-
- var spyObj = jasmine.createSpy(methodName);
-
- this.spies_.push(spyObj);
- spyObj.baseObj = obj;
- spyObj.methodName = methodName;
- spyObj.originalValue = obj[methodName];
-
- obj[methodName] = spyObj;
-
- return spyObj;
-};
-
-jasmine.Spec.prototype.removeAllSpies = function() {
- for (var i = 0; i < this.spies_.length; i++) {
- var spy = this.spies_[i];
- spy.baseObj[spy.methodName] = spy.originalValue;
- }
- this.spies_ = [];
-};
-
-/**
- * Internal representation of a Jasmine suite.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {String} description
- * @param {Function} specDefinitions
- * @param {jasmine.Suite} parentSuite
- */
-jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
- var self = this;
- self.id = env.nextSuiteId ? env.nextSuiteId() : null;
- self.description = description;
- self.queue = new jasmine.Queue(env);
- self.parentSuite = parentSuite;
- self.env = env;
- self.before_ = [];
- self.after_ = [];
- self.children_ = [];
- self.suites_ = [];
- self.specs_ = [];
-};
-
-jasmine.Suite.prototype.getFullName = function() {
- var fullName = this.description;
- for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
- fullName = parentSuite.description + ' ' + fullName;
- }
- return fullName;
-};
-
-jasmine.Suite.prototype.finish = function(onComplete) {
- this.env.reporter.reportSuiteResults(this);
- this.finished = true;
- if (typeof(onComplete) == 'function') {
- onComplete();
- }
-};
-
-jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
- beforeEachFunction.typeName = 'beforeEach';
- this.before_.unshift(beforeEachFunction);
-};
-
-jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
- afterEachFunction.typeName = 'afterEach';
- this.after_.unshift(afterEachFunction);
-};
-
-jasmine.Suite.prototype.results = function() {
- return this.queue.results();
-};
-
-jasmine.Suite.prototype.add = function(suiteOrSpec) {
- this.children_.push(suiteOrSpec);
- if (suiteOrSpec instanceof jasmine.Suite) {
- this.suites_.push(suiteOrSpec);
- this.env.currentRunner().addSuite(suiteOrSpec);
- } else {
- this.specs_.push(suiteOrSpec);
- }
- this.queue.add(suiteOrSpec);
-};
-
-jasmine.Suite.prototype.specs = function() {
- return this.specs_;
-};
-
-jasmine.Suite.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.Suite.prototype.children = function() {
- return this.children_;
-};
-
-jasmine.Suite.prototype.execute = function(onComplete) {
- var self = this;
- this.queue.start(function () {
- self.finish(onComplete);
- });
-};
-jasmine.WaitsBlock = function(env, timeout, spec) {
- this.timeout = timeout;
- jasmine.Block.call(this, env, null, spec);
-};
-
-jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
-
-jasmine.WaitsBlock.prototype.execute = function (onComplete) {
- if (jasmine.VERBOSE) {
- this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
- }
- this.env.setTimeout(function () {
- onComplete();
- }, this.timeout);
-};
-/**
- * A block which waits for some condition to become true, with timeout.
- *
- * @constructor
- * @extends jasmine.Block
- * @param {jasmine.Env} env The Jasmine environment.
- * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
- * @param {Function} latchFunction A function which returns true when the desired condition has been met.
- * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
- * @param {jasmine.Spec} spec The Jasmine spec.
- */
-jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
- this.timeout = timeout || env.defaultTimeoutInterval;
- this.latchFunction = latchFunction;
- this.message = message;
- this.totalTimeSpentWaitingForLatch = 0;
- jasmine.Block.call(this, env, null, spec);
-};
-jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
-
-jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
-
-jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
- if (jasmine.VERBOSE) {
- this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
- }
- var latchFunctionResult;
- try {
- latchFunctionResult = this.latchFunction.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
- onComplete();
- return;
- }
-
- if (latchFunctionResult) {
- onComplete();
- } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
- var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
- this.spec.fail({
- name: 'timeout',
- message: message
- });
-
- this.abort = true;
- onComplete();
- } else {
- this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
- var self = this;
- this.env.setTimeout(function() {
- self.execute(onComplete);
- }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
- }
-};
-
-jasmine.version_= {
- "major": 1,
- "minor": 3,
- "build": 1,
- "revision": 1354556913
-};
+++ /dev/null
-/*!
- * LESS - Leaner CSS v1.5.0
- * http://lesscss.org
- *
- * Copyright (c) 2009-2013, Alexis Sellier <self@cloudhead.net>
- * Licensed under the Apache v2 License.
- *
- * @licence
- */
-
-
-
-(function (window, undefined) {//
-// Stub out `require` in the browser
-//
-function require(arg) {
- return window.less[arg.split('/')[1]];
-};
-
-
-if (typeof(window.less) === 'undefined' || typeof(window.less.nodeType) !== 'undefined') { window.less = {}; }
-less = window.less;
-tree = window.less.tree = {};
-less.mode = 'browser';
-
-var less, tree;
-
-// Node.js does not have a header file added which defines less
-if (less === undefined) {
- less = exports;
- tree = require('./tree');
- less.mode = 'node';
-}
-//
-// less.js - parser
-//
-// A relatively straight-forward predictive parser.
-// There is no tokenization/lexing stage, the input is parsed
-// in one sweep.
-//
-// To make the parser fast enough to run in the browser, several
-// optimization had to be made:
-//
-// - Matching and slicing on a huge input is often cause of slowdowns.
-// The solution is to chunkify the input into smaller strings.
-// The chunks are stored in the `chunks` var,
-// `j` holds the current chunk index, and `current` holds
-// the index of the current chunk in relation to `input`.
-// This gives us an almost 4x speed-up.
-//
-// - In many cases, we don't need to match individual tokens;
-// for example, if a value doesn't hold any variables, operations
-// or dynamic references, the parser can effectively 'skip' it,
-// treating it as a literal.
-// An example would be '1px solid #000' - which evaluates to itself,
-// we don't need to know what the individual components are.
-// The drawback, of course is that you don't get the benefits of
-// syntax-checking on the CSS. This gives us a 50% speed-up in the parser,
-// and a smaller speed-up in the code-gen.
-//
-//
-// Token matching is done with the `$` function, which either takes
-// a terminal string or regexp, or a non-terminal function to call.
-// It also takes care of moving all the indices forwards.
-//
-//
-less.Parser = function Parser(env) {
- var input, // LeSS input string
- i, // current index in `input`
- j, // current chunk
- temp, // temporarily holds a chunk's state, for backtracking
- memo, // temporarily holds `i`, when backtracking
- furthest, // furthest index the parser has gone to
- chunks, // chunkified input
- current, // index of current chunk, in `input`
- parser,
- rootFilename = env && env.filename;
-
- // Top parser on an import tree must be sure there is one "env"
- // which will then be passed around by reference.
- if (!(env instanceof tree.parseEnv)) {
- env = new tree.parseEnv(env);
- }
-
- var imports = this.imports = {
- paths: env.paths || [], // Search paths, when importing
- queue: [], // Files which haven't been imported yet
- files: env.files, // Holds the imported parse trees
- contents: env.contents, // Holds the imported file contents
- mime: env.mime, // MIME type of .less files
- error: null, // Error in parsing/evaluating an import
- push: function (path, currentFileInfo, importOptions, callback) {
- var parserImports = this;
- this.queue.push(path);
-
- var fileParsedFunc = function (e, root, fullPath) {
- parserImports.queue.splice(parserImports.queue.indexOf(path), 1); // Remove the path from the queue
-
- var importedPreviously = fullPath in parserImports.files || fullPath === rootFilename;
-
- parserImports.files[fullPath] = root; // Store the root
-
- if (e && !parserImports.error) { parserImports.error = e; }
-
- callback(e, root, importedPreviously, fullPath);
- };
-
- if (less.Parser.importer) {
- less.Parser.importer(path, currentFileInfo, fileParsedFunc, env);
- } else {
- less.Parser.fileLoader(path, currentFileInfo, function(e, contents, fullPath, newFileInfo) {
- if (e) {fileParsedFunc(e); return;}
-
- var newEnv = new tree.parseEnv(env);
-
- newEnv.currentFileInfo = newFileInfo;
- newEnv.processImports = false;
- newEnv.contents[fullPath] = contents;
-
- if (currentFileInfo.reference || importOptions.reference) {
- newFileInfo.reference = true;
- }
-
- if (importOptions.inline) {
- fileParsedFunc(null, contents, fullPath);
- } else {
- new(less.Parser)(newEnv).parse(contents, function (e, root) {
- fileParsedFunc(e, root, fullPath);
- });
- }
- }, env);
- }
- }
- };
-
- function save() { temp = chunks[j], memo = i, current = i; }
- function restore() { chunks[j] = temp, i = memo, current = i; }
-
- function sync() {
- if (i > current) {
- chunks[j] = chunks[j].slice(i - current);
- current = i;
- }
- }
- function isWhitespace(c) {
- // Could change to \s?
- var code = c.charCodeAt(0);
- return code === 32 || code === 10 || code === 9;
- }
- //
- // Parse from a token, regexp or string, and move forward if match
- //
- function $(tok) {
- var match, length;
-
- //
- // Non-terminal
- //
- if (tok instanceof Function) {
- return tok.call(parser.parsers);
- //
- // Terminal
- //
- // Either match a single character in the input,
- // or match a regexp in the current chunk (chunk[j]).
- //
- } else if (typeof(tok) === 'string') {
- match = input.charAt(i) === tok ? tok : null;
- length = 1;
- sync ();
- } else {
- sync ();
-
- if (match = tok.exec(chunks[j])) {
- length = match[0].length;
- } else {
- return null;
- }
- }
-
- // The match is confirmed, add the match length to `i`,
- // and consume any extra white-space characters (' ' || '\n')
- // which come after that. The reason for this is that LeSS's
- // grammar is mostly white-space insensitive.
- //
- if (match) {
- skipWhitespace(length);
-
- if(typeof(match) === 'string') {
- return match;
- } else {
- return match.length === 1 ? match[0] : match;
- }
- }
- }
-
- function skipWhitespace(length) {
- var oldi = i, oldj = j,
- endIndex = i + chunks[j].length,
- mem = i += length;
-
- while (i < endIndex) {
- if (! isWhitespace(input.charAt(i))) { break; }
- i++;
- }
- chunks[j] = chunks[j].slice(length + (i - mem));
- current = i;
-
- if (chunks[j].length === 0 && j < chunks.length - 1) { j++; }
-
- return oldi !== i || oldj !== j;
- }
-
- function expect(arg, msg) {
- var result = $(arg);
- if (! result) {
- error(msg || (typeof(arg) === 'string' ? "expected '" + arg + "' got '" + input.charAt(i) + "'"
- : "unexpected token"));
- } else {
- return result;
- }
- }
-
- function error(msg, type) {
- var e = new Error(msg);
- e.index = i;
- e.type = type || 'Syntax';
- throw e;
- }
-
- // Same as $(), but don't change the state of the parser,
- // just return the match.
- function peek(tok) {
- if (typeof(tok) === 'string') {
- return input.charAt(i) === tok;
- } else {
- return tok.test(chunks[j]);
- }
- }
-
- function getInput(e, env) {
- if (e.filename && env.currentFileInfo.filename && (e.filename !== env.currentFileInfo.filename)) {
- return parser.imports.contents[e.filename];
- } else {
- return input;
- }
- }
-
- function getLocation(index, inputStream) {
- var n = index + 1,
- line = null,
- column = -1;
-
- while (--n >= 0 && inputStream.charAt(n) !== '\n') {
- column++;
- }
-
- if (typeof index === 'number') {
- line = (inputStream.slice(0, index).match(/\n/g) || "").length;
- }
-
- return {
- line: line,
- column: column
- };
- }
-
- function getDebugInfo(index, inputStream, env) {
- var filename = env.currentFileInfo.filename;
- if(less.mode !== 'browser' && less.mode !== 'rhino') {
- filename = require('path').resolve(filename);
- }
-
- return {
- lineNumber: getLocation(index, inputStream).line + 1,
- fileName: filename
- };
- }
-
- function LessError(e, env) {
- var input = getInput(e, env),
- loc = getLocation(e.index, input),
- line = loc.line,
- col = loc.column,
- callLine = e.call && getLocation(e.call, input).line,
- lines = input.split('\n');
-
- this.type = e.type || 'Syntax';
- this.message = e.message;
- this.filename = e.filename || env.currentFileInfo.filename;
- this.index = e.index;
- this.line = typeof(line) === 'number' ? line + 1 : null;
- this.callLine = callLine + 1;
- this.callExtract = lines[callLine];
- this.stack = e.stack;
- this.column = col;
- this.extract = [
- lines[line - 1],
- lines[line],
- lines[line + 1]
- ];
- }
-
- LessError.prototype = new Error();
- LessError.prototype.constructor = LessError;
-
- this.env = env = env || {};
-
- // The optimization level dictates the thoroughness of the parser,
- // the lower the number, the less nodes it will create in the tree.
- // This could matter for debugging, or if you want to access
- // the individual nodes in the tree.
- this.optimization = ('optimization' in this.env) ? this.env.optimization : 1;
-
- //
- // The Parser
- //
- return parser = {
-
- imports: imports,
- //
- // Parse an input string into an abstract syntax tree,
- // call `callback` when done.
- //
- parse: function (str, callback) {
- var root, line, lines, error = null;
-
- i = j = current = furthest = 0;
- input = str.replace(/\r\n/g, '\n');
-
- // Remove potential UTF Byte Order Mark
- input = input.replace(/^\uFEFF/, '');
-
- parser.imports.contents[env.currentFileInfo.filename] = input;
-
- // Split the input into chunks.
- chunks = (function (chunks) {
- var j = 0,
- skip = /(?:@\{[\w-]+\}|[^"'`\{\}\/\(\)\\])+/g,
- comment = /\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,
- string = /"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'|`((?:[^`]|\\.)*)`/g,
- level = 0,
- match,
- chunk = chunks[0],
- inParam;
-
- for (var i = 0, c, cc; i < input.length;) {
- skip.lastIndex = i;
- if (match = skip.exec(input)) {
- if (match.index === i) {
- i += match[0].length;
- chunk.push(match[0]);
- }
- }
- c = input.charAt(i);
- comment.lastIndex = string.lastIndex = i;
-
- if (match = string.exec(input)) {
- if (match.index === i) {
- i += match[0].length;
- chunk.push(match[0]);
- continue;
- }
- }
-
- if (!inParam && c === '/') {
- cc = input.charAt(i + 1);
- if (cc === '/' || cc === '*') {
- if (match = comment.exec(input)) {
- if (match.index === i) {
- i += match[0].length;
- chunk.push(match[0]);
- continue;
- }
- }
- }
- }
-
- switch (c) {
- case '{':
- if (!inParam) {
- level++;
- chunk.push(c);
- break;
- }
- /* falls through */
- case '}':
- if (!inParam) {
- level--;
- chunk.push(c);
- chunks[++j] = chunk = [];
- break;
- }
- /* falls through */
- case '(':
- if (!inParam) {
- inParam = true;
- chunk.push(c);
- break;
- }
- /* falls through */
- case ')':
- if (inParam) {
- inParam = false;
- chunk.push(c);
- break;
- }
- /* falls through */
- default:
- chunk.push(c);
- }
-
- i++;
- }
- if (level !== 0) {
- error = new(LessError)({
- index: i-1,
- type: 'Parse',
- message: (level > 0) ? "missing closing `}`" : "missing opening `{`",
- filename: env.currentFileInfo.filename
- }, env);
- }
-
- return chunks.map(function (c) { return c.join(''); });
- })([[]]);
-
- if (error) {
- return callback(new(LessError)(error, env));
- }
-
- // Start with the primary rule.
- // The whole syntax tree is held under a Ruleset node,
- // with the `root` property set to true, so no `{}` are
- // output. The callback is called when the input is parsed.
- try {
- root = new(tree.Ruleset)([], $(this.parsers.primary));
- root.root = true;
- root.firstRoot = true;
- } catch (e) {
- return callback(new(LessError)(e, env));
- }
-
- root.toCSS = (function (evaluate) {
- return function (options, variables) {
- options = options || {};
- var evaldRoot,
- css,
- evalEnv = new tree.evalEnv(options);
-
- //
- // Allows setting variables with a hash, so:
- //
- // `{ color: new(tree.Color)('#f01') }` will become:
- //
- // new(tree.Rule)('@color',
- // new(tree.Value)([
- // new(tree.Expression)([
- // new(tree.Color)('#f01')
- // ])
- // ])
- // )
- //
- if (typeof(variables) === 'object' && !Array.isArray(variables)) {
- variables = Object.keys(variables).map(function (k) {
- var value = variables[k];
-
- if (! (value instanceof tree.Value)) {
- if (! (value instanceof tree.Expression)) {
- value = new(tree.Expression)([value]);
- }
- value = new(tree.Value)([value]);
- }
- return new(tree.Rule)('@' + k, value, false, null, 0);
- });
- evalEnv.frames = [new(tree.Ruleset)(null, variables)];
- }
-
- try {
- evaldRoot = evaluate.call(this, evalEnv);
-
- new(tree.joinSelectorVisitor)()
- .run(evaldRoot);
-
- new(tree.processExtendsVisitor)()
- .run(evaldRoot);
-
- new(tree.toCSSVisitor)({compress: Boolean(options.compress)})
- .run(evaldRoot);
-
- if (options.sourceMap) {
- evaldRoot = new tree.sourceMapOutput(
- {
- writeSourceMap: options.writeSourceMap,
- rootNode: evaldRoot,
- contentsMap: parser.imports.contents,
- sourceMapFilename: options.sourceMapFilename,
- outputFilename: options.sourceMapOutputFilename,
- sourceMapBasepath: options.sourceMapBasepath,
- sourceMapRootpath: options.sourceMapRootpath,
- outputSourceFiles: options.outputSourceFiles,
- sourceMapGenerator: options.sourceMapGenerator
- });
- }
-
- css = evaldRoot.toCSS({
- compress: Boolean(options.compress),
- dumpLineNumbers: env.dumpLineNumbers,
- strictUnits: Boolean(options.strictUnits)});
- } catch (e) {
- throw new(LessError)(e, env);
- }
-
- if (options.cleancss && less.mode === 'node') {
- var CleanCSS = require('clean-css');
- //TODO would be nice for no advanced to be an option
- return new CleanCSS({keepSpecialComments: '*', processImport: false, noRebase: true, noAdvanced: true}).minify(css);
- } else if (options.compress) {
- return css.replace(/(^(\s)+)|((\s)+$)/g, "");
- } else {
- return css;
- }
- };
- })(root.eval);
-
- // If `i` is smaller than the `input.length - 1`,
- // it means the parser wasn't able to parse the whole
- // string, so we've got a parsing error.
- //
- // We try to extract a \n delimited string,
- // showing the line where the parse error occured.
- // We split it up into two parts (the part which parsed,
- // and the part which didn't), so we can color them differently.
- if (i < input.length - 1) {
- i = furthest;
- var loc = getLocation(i, input);
- lines = input.split('\n');
- line = loc.line + 1;
-
- error = {
- type: "Parse",
- message: "Unrecognised input",
- index: i,
- filename: env.currentFileInfo.filename,
- line: line,
- column: loc.column,
- extract: [
- lines[line - 2],
- lines[line - 1],
- lines[line]
- ]
- };
- }
-
- var finish = function (e) {
- e = error || e || parser.imports.error;
-
- if (e) {
- if (!(e instanceof LessError)) {
- e = new(LessError)(e, env);
- }
-
- return callback(e);
- }
- else {
- return callback(null, root);
- }
- };
-
- if (env.processImports !== false) {
- new tree.importVisitor(this.imports, finish)
- .run(root);
- } else {
- return finish();
- }
- },
-
- //
- // Here in, the parsing rules/functions
- //
- // The basic structure of the syntax tree generated is as follows:
- //
- // Ruleset -> Rule -> Value -> Expression -> Entity
- //
- // Here's some LESS code:
- //
- // .class {
- // color: #fff;
- // border: 1px solid #000;
- // width: @w + 4px;
- // > .child {...}
- // }
- //
- // And here's what the parse tree might look like:
- //
- // Ruleset (Selector '.class', [
- // Rule ("color", Value ([Expression [Color #fff]]))
- // Rule ("border", Value ([Expression [Dimension 1px][Keyword "solid"][Color #000]]))
- // Rule ("width", Value ([Expression [Operation "+" [Variable "@w"][Dimension 4px]]]))
- // Ruleset (Selector [Element '>', '.child'], [...])
- // ])
- //
- // In general, most rules will try to parse a token with the `$()` function, and if the return
- // value is truly, will return a new node, of the relevant type. Sometimes, we need to check
- // first, before parsing, that's when we use `peek()`.
- //
- parsers: {
- //
- // The `primary` rule is the *entry* and *exit* point of the parser.
- // The rules here can appear at any level of the parse tree.
- //
- // The recursive nature of the grammar is an interplay between the `block`
- // rule, which represents `{ ... }`, the `ruleset` rule, and this `primary` rule,
- // as represented by this simplified grammar:
- //
- // primary → (ruleset | rule)+
- // ruleset → selector+ block
- // block → '{' primary '}'
- //
- // Only at one point is the primary rule not called from the
- // block rule: at the root level.
- //
- primary: function () {
- var node, root = [];
-
- while ((node = $(this.extendRule) || $(this.mixin.definition) || $(this.rule) || $(this.ruleset) ||
- $(this.mixin.call) || $(this.comment) || $(this.directive))
- || $(/^[\s\n]+/) || $(/^;+/)) {
- node && root.push(node);
- }
- return root;
- },
-
- // We create a Comment node for CSS comments `/* */`,
- // but keep the LeSS comments `//` silent, by just skipping
- // over them.
- comment: function () {
- var comment;
-
- if (input.charAt(i) !== '/') { return; }
-
- if (input.charAt(i + 1) === '/') {
- return new(tree.Comment)($(/^\/\/.*/), true, i, env.currentFileInfo);
- } else if (comment = $(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/)) {
- return new(tree.Comment)(comment, false, i, env.currentFileInfo);
- }
- },
-
- comments: function () {
- var comment, comments = [];
-
- while(comment = $(this.comment)) {
- comments.push(comment);
- }
-
- return comments;
- },
-
- //
- // Entities are tokens which can be found inside an Expression
- //
- entities: {
- //
- // A string, which supports escaping " and '
- //
- // "milky way" 'he\'s the one!'
- //
- quoted: function () {
- var str, j = i, e, index = i;
-
- if (input.charAt(j) === '~') { j++, e = true; } // Escaped strings
- if (input.charAt(j) !== '"' && input.charAt(j) !== "'") { return; }
-
- e && $('~');
-
- if (str = $(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/)) {
- return new(tree.Quoted)(str[0], str[1] || str[2], e, index, env.currentFileInfo);
- }
- },
-
- //
- // A catch-all word, such as:
- //
- // black border-collapse
- //
- keyword: function () {
- var k;
-
- if (k = $(/^[_A-Za-z-][_A-Za-z0-9-]*/)) {
- var color = tree.Color.fromKeyword(k);
- if (color) {
- return color;
- }
- return new(tree.Keyword)(k);
- }
- },
-
- //
- // A function call
- //
- // rgb(255, 0, 255)
- //
- // We also try to catch IE's `alpha()`, but let the `alpha` parser
- // deal with the details.
- //
- // The arguments are parsed with the `entities.arguments` parser.
- //
- call: function () {
- var name, nameLC, args, alpha_ret, index = i;
-
- if (! (name = /^([\w-]+|%|progid:[\w\.]+)\(/.exec(chunks[j]))) { return; }
-
- name = name[1];
- nameLC = name.toLowerCase();
-
- if (nameLC === 'url') { return null; }
- else { i += name.length; }
-
- if (nameLC === 'alpha') {
- alpha_ret = $(this.alpha);
- if(typeof alpha_ret !== 'undefined') {
- return alpha_ret;
- }
- }
-
- $('('); // Parse the '(' and consume whitespace.
-
- args = $(this.entities.arguments);
-
- if (! $(')')) {
- return;
- }
-
- if (name) { return new(tree.Call)(name, args, index, env.currentFileInfo); }
- },
- arguments: function () {
- var args = [], arg;
-
- while (arg = $(this.entities.assignment) || $(this.expression)) {
- args.push(arg);
- if (! $(',')) {
- break;
- }
- }
- return args;
- },
- literal: function () {
- return $(this.entities.dimension) ||
- $(this.entities.color) ||
- $(this.entities.quoted) ||
- $(this.entities.unicodeDescriptor);
- },
-
- // Assignments are argument entities for calls.
- // They are present in ie filter properties as shown below.
- //
- // filter: progid:DXImageTransform.Microsoft.Alpha( *opacity=50* )
- //
-
- assignment: function () {
- var key, value;
- if ((key = $(/^\w+(?=\s?=)/i)) && $('=') && (value = $(this.entity))) {
- return new(tree.Assignment)(key, value);
- }
- },
-
- //
- // Parse url() tokens
- //
- // We use a specific rule for urls, because they don't really behave like
- // standard function calls. The difference is that the argument doesn't have
- // to be enclosed within a string, so it can't be parsed as an Expression.
- //
- url: function () {
- var value;
-
- if (input.charAt(i) !== 'u' || !$(/^url\(/)) {
- return;
- }
-
- value = $(this.entities.quoted) || $(this.entities.variable) ||
- $(/^(?:(?:\\[\(\)'"])|[^\(\)'"])+/) || "";
-
- expect(')');
-
- /*jshint eqnull:true */
- return new(tree.URL)((value.value != null || value instanceof tree.Variable)
- ? value : new(tree.Anonymous)(value), env.currentFileInfo);
- },
-
- //
- // A Variable entity, such as `@fink`, in
- //
- // width: @fink + 2px
- //
- // We use a different parser for variable definitions,
- // see `parsers.variable`.
- //
- variable: function () {
- var name, index = i;
-
- if (input.charAt(i) === '@' && (name = $(/^@@?[\w-]+/))) {
- return new(tree.Variable)(name, index, env.currentFileInfo);
- }
- },
-
- // A variable entity useing the protective {} e.g. @{var}
- variableCurly: function () {
- var curly, index = i;
-
- if (input.charAt(i) === '@' && (curly = $(/^@\{([\w-]+)\}/))) {
- return new(tree.Variable)("@" + curly[1], index, env.currentFileInfo);
- }
- },
-
- //
- // A Hexadecimal color
- //
- // #4F3C2F
- //
- // `rgb` and `hsl` colors are parsed through the `entities.call` parser.
- //
- color: function () {
- var rgb;
-
- if (input.charAt(i) === '#' && (rgb = $(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/))) {
- return new(tree.Color)(rgb[1]);
- }
- },
-
- //
- // A Dimension, that is, a number and a unit
- //
- // 0.5em 95%
- //
- dimension: function () {
- var value, c = input.charCodeAt(i);
- //Is the first char of the dimension 0-9, '.', '+' or '-'
- if ((c > 57 || c < 43) || c === 47 || c == 44) {
- return;
- }
-
- if (value = $(/^([+-]?\d*\.?\d+)(%|[a-z]+)?/)) {
- return new(tree.Dimension)(value[1], value[2]);
- }
- },
-
- //
- // A unicode descriptor, as is used in unicode-range
- //
- // U+0?? or U+00A1-00A9
- //
- unicodeDescriptor: function () {
- var ud;
-
- if (ud = $(/^U\+[0-9a-fA-F?]+(\-[0-9a-fA-F?]+)?/)) {
- return new(tree.UnicodeDescriptor)(ud[0]);
- }
- },
-
- //
- // JavaScript code to be evaluated
- //
- // `window.location.href`
- //
- javascript: function () {
- var str, j = i, e;
-
- if (input.charAt(j) === '~') { j++; e = true; } // Escaped strings
- if (input.charAt(j) !== '`') { return; }
- if (env.javascriptEnabled !== undefined && !env.javascriptEnabled) {
- error("You are using JavaScript, which has been disabled.");
- }
-
- if (e) { $('~'); }
-
- if (str = $(/^`([^`]*)`/)) {
- return new(tree.JavaScript)(str[1], i, e);
- }
- }
- },
-
- //
- // The variable part of a variable definition. Used in the `rule` parser
- //
- // @fink:
- //
- variable: function () {
- var name;
-
- if (input.charAt(i) === '@' && (name = $(/^(@[\w-]+)\s*:/))) { return name[1]; }
- },
-
- //
- // extend syntax - used to extend selectors
- //
- extend: function(isRule) {
- var elements, e, index = i, option, extendList = [];
-
- if (!$(isRule ? /^&:extend\(/ : /^:extend\(/)) { return; }
-
- do {
- option = null;
- elements = [];
- while (true) {
- option = $(/^(all)(?=\s*(\)|,))/);
- if (option) { break; }
- e = $(this.element);
- if (!e) { break; }
- elements.push(e);
- }
-
- option = option && option[1];
-
- extendList.push(new(tree.Extend)(new(tree.Selector)(elements), option, index));
-
- } while($(","));
-
- expect(/^\)/);
-
- if (isRule) {
- expect(/^;/);
- }
-
- return extendList;
- },
-
- //
- // extendRule - used in a rule to extend all the parent selectors
- //
- extendRule: function() {
- return this.extend(true);
- },
-
- //
- // Mixins
- //
- mixin: {
- //
- // A Mixin call, with an optional argument list
- //
- // #mixins > .square(#fff);
- // .rounded(4px, black);
- // .button;
- //
- // The `while` loop is there because mixins can be
- // namespaced, but we only support the child and descendant
- // selector for now.
- //
- call: function () {
- var elements = [], e, c, args, index = i, s = input.charAt(i), important = false;
-
- if (s !== '.' && s !== '#') { return; }
-
- save(); // stop us absorbing part of an invalid selector
-
- while (e = $(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)) {
- elements.push(new(tree.Element)(c, e, i, env.currentFileInfo));
- c = $('>');
- }
- if ($('(')) {
- args = this.mixin.args.call(this, true).args;
- expect(')');
- }
-
- args = args || [];
-
- if ($(this.important)) {
- important = true;
- }
-
- if (elements.length > 0 && ($(';') || peek('}'))) {
- return new(tree.mixin.Call)(elements, args, index, env.currentFileInfo, important);
- }
-
- restore();
- },
- args: function (isCall) {
- var expressions = [], argsSemiColon = [], isSemiColonSeperated, argsComma = [], expressionContainsNamed, name, nameLoop, value, arg,
- returner = {args:null, variadic: false};
- while (true) {
- if (isCall) {
- arg = $(this.expression);
- } else {
- $(this.comments);
- if (input.charAt(i) === '.' && $(/^\.{3}/)) {
- returner.variadic = true;
- if ($(";") && !isSemiColonSeperated) {
- isSemiColonSeperated = true;
- }
- (isSemiColonSeperated ? argsSemiColon : argsComma)
- .push({ variadic: true });
- break;
- }
- arg = $(this.entities.variable) || $(this.entities.literal)
- || $(this.entities.keyword);
- }
-
- if (!arg) {
- break;
- }
-
- nameLoop = null;
- if (arg.throwAwayComments) {
- arg.throwAwayComments();
- }
- value = arg;
- var val = null;
-
- if (isCall) {
- // Variable
- if (arg.value.length == 1) {
- val = arg.value[0];
- }
- } else {
- val = arg;
- }
-
- if (val && val instanceof tree.Variable) {
- if ($(':')) {
- if (expressions.length > 0) {
- if (isSemiColonSeperated) {
- error("Cannot mix ; and , as delimiter types");
- }
- expressionContainsNamed = true;
- }
- value = expect(this.expression);
- nameLoop = (name = val.name);
- } else if (!isCall && $(/^\.{3}/)) {
- returner.variadic = true;
- if ($(";") && !isSemiColonSeperated) {
- isSemiColonSeperated = true;
- }
- (isSemiColonSeperated ? argsSemiColon : argsComma)
- .push({ name: arg.name, variadic: true });
- break;
- } else if (!isCall) {
- name = nameLoop = val.name;
- value = null;
- }
- }
-
- if (value) {
- expressions.push(value);
- }
-
- argsComma.push({ name:nameLoop, value:value });
-
- if ($(',')) {
- continue;
- }
-
- if ($(';') || isSemiColonSeperated) {
-
- if (expressionContainsNamed) {
- error("Cannot mix ; and , as delimiter types");
- }
-
- isSemiColonSeperated = true;
-
- if (expressions.length > 1) {
- value = new(tree.Value)(expressions);
- }
- argsSemiColon.push({ name:name, value:value });
-
- name = null;
- expressions = [];
- expressionContainsNamed = false;
- }
- }
-
- returner.args = isSemiColonSeperated ? argsSemiColon : argsComma;
- return returner;
- },
- //
- // A Mixin definition, with a list of parameters
- //
- // .rounded (@radius: 2px, @color) {
- // ...
- // }
- //
- // Until we have a finer grained state-machine, we have to
- // do a look-ahead, to make sure we don't have a mixin call.
- // See the `rule` function for more information.
- //
- // We start by matching `.rounded (`, and then proceed on to
- // the argument list, which has optional default values.
- // We store the parameters in `params`, with a `value` key,
- // if there is a value, such as in the case of `@radius`.
- //
- // Once we've got our params list, and a closing `)`, we parse
- // the `{...}` block.
- //
- definition: function () {
- var name, params = [], match, ruleset, cond, variadic = false;
- if ((input.charAt(i) !== '.' && input.charAt(i) !== '#') ||
- peek(/^[^{]*\}/)) {
- return;
- }
-
- save();
-
- if (match = $(/^([#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+)\s*\(/)) {
- name = match[1];
-
- var argInfo = this.mixin.args.call(this, false);
- params = argInfo.args;
- variadic = argInfo.variadic;
-
- // .mixincall("@{a}");
- // looks a bit like a mixin definition.. so we have to be nice and restore
- if (!$(')')) {
- furthest = i;
- restore();
- }
-
- $(this.comments);
-
- if ($(/^when/)) { // Guard
- cond = expect(this.conditions, 'expected condition');
- }
-
- ruleset = $(this.block);
-
- if (ruleset) {
- return new(tree.mixin.Definition)(name, params, ruleset, cond, variadic);
- } else {
- restore();
- }
- }
- }
- },
-
- //
- // Entities are the smallest recognized token,
- // and can be found inside a rule's value.
- //
- entity: function () {
- return $(this.entities.literal) || $(this.entities.variable) || $(this.entities.url) ||
- $(this.entities.call) || $(this.entities.keyword) ||$(this.entities.javascript) ||
- $(this.comment);
- },
-
- //
- // A Rule terminator. Note that we use `peek()` to check for '}',
- // because the `block` rule will be expecting it, but we still need to make sure
- // it's there, if ';' was ommitted.
- //
- end: function () {
- return $(';') || peek('}');
- },
-
- //
- // IE's alpha function
- //
- // alpha(opacity=88)
- //
- alpha: function () {
- var value;
-
- if (! $(/^\(opacity=/i)) { return; }
- if (value = $(/^\d+/) || $(this.entities.variable)) {
- expect(')');
- return new(tree.Alpha)(value);
- }
- },
-
- //
- // A Selector Element
- //
- // div
- // + h1
- // #socks
- // input[type="text"]
- //
- // Elements are the building blocks for Selectors,
- // they are made out of a `Combinator` (see combinator rule),
- // and an element name, such as a tag a class, or `*`.
- //
- element: function () {
- var e, c, v;
-
- c = $(this.combinator);
-
- e = $(/^(?:\d+\.\d+|\d+)%/) || $(/^(?:[.#]?|:*)(?:[\w-]|[^\x00-\x9f]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/) ||
- $('*') || $('&') || $(this.attribute) || $(/^\([^()@]+\)/) || $(/^[\.#](?=@)/) || $(this.entities.variableCurly);
-
- if (! e) {
- if ($('(')) {
- if ((v = ($(this.selector))) &&
- $(')')) {
- e = new(tree.Paren)(v);
- }
- }
- }
-
- if (e) { return new(tree.Element)(c, e, i, env.currentFileInfo); }
- },
-
- //
- // Combinators combine elements together, in a Selector.
- //
- // Because our parser isn't white-space sensitive, special care
- // has to be taken, when parsing the descendant combinator, ` `,
- // as it's an empty space. We have to check the previous character
- // in the input, to see if it's a ` ` character. More info on how
- // we deal with this in *combinator.js*.
- //
- combinator: function () {
- var c = input.charAt(i);
-
- if (c === '>' || c === '+' || c === '~' || c === '|') {
- i++;
- while (input.charAt(i).match(/\s/)) { i++; }
- return new(tree.Combinator)(c);
- } else if (input.charAt(i - 1).match(/\s/)) {
- return new(tree.Combinator)(" ");
- } else {
- return new(tree.Combinator)(null);
- }
- },
- //
- // A CSS selector (see selector below)
- // with less extensions e.g. the ability to extend and guard
- //
- lessSelector: function () {
- return this.selector(true);
- },
- //
- // A CSS Selector
- //
- // .class > div + h1
- // li a:hover
- //
- // Selectors are made out of one or more Elements, see above.
- //
- selector: function (isLess) {
- var e, elements = [], c, extend, extendList = [], when, condition;
-
- while ((isLess && (extend = $(this.extend))) || (isLess && (when = $(/^when/))) || (e = $(this.element))) {
- if (when) {
- condition = expect(this.conditions, 'expected condition');
- } else if (condition) {
- error("CSS guard can only be used at the end of selector");
- } else if (extend) {
- extendList.push.apply(extendList, extend);
- } else {
- if (extendList.length) {
- error("Extend can only be used at the end of selector");
- }
- c = input.charAt(i);
- elements.push(e);
- e = null;
- }
- if (c === '{' || c === '}' || c === ';' || c === ',' || c === ')') {
- break;
- }
- }
-
- if (elements.length > 0) { return new(tree.Selector)(elements, extendList, condition, i, env.currentFileInfo); }
- if (extendList.length) { error("Extend must be used to extend a selector, it cannot be used on its own"); }
- },
- attribute: function () {
- var key, val, op;
-
- if (! $('[')) { return; }
-
- if (!(key = $(this.entities.variableCurly))) {
- key = expect(/^(?:[_A-Za-z0-9-\*]*\|)?(?:[_A-Za-z0-9-]|\\.)+/);
- }
-
- if ((op = $(/^[|~*$^]?=/))) {
- val = $(this.entities.quoted) || $(/^[0-9]+%/) || $(/^[\w-]+/) || $(this.entities.variableCurly);
- }
-
- expect(']');
-
- return new(tree.Attribute)(key, op, val);
- },
-
- //
- // The `block` rule is used by `ruleset` and `mixin.definition`.
- // It's a wrapper around the `primary` rule, with added `{}`.
- //
- block: function () {
- var content;
- if ($('{') && (content = $(this.primary)) && $('}')) {
- return content;
- }
- },
-
- //
- // div, .class, body > p {...}
- //
- ruleset: function () {
- var selectors = [], s, rules, debugInfo;
-
- save();
-
- if (env.dumpLineNumbers) {
- debugInfo = getDebugInfo(i, input, env);
- }
-
- while (s = $(this.lessSelector)) {
- selectors.push(s);
- $(this.comments);
- if (! $(',')) { break; }
- if (s.condition) {
- error("Guards are only currently allowed on a single selector.");
- }
- $(this.comments);
- }
-
- if (selectors.length > 0 && (rules = $(this.block))) {
- var ruleset = new(tree.Ruleset)(selectors, rules, env.strictImports);
- if (env.dumpLineNumbers) {
- ruleset.debugInfo = debugInfo;
- }
- return ruleset;
- } else {
- // Backtrack
- furthest = i;
- restore();
- }
- },
- rule: function (tryAnonymous) {
- var name, value, c = input.charAt(i), important, merge = false;
- save();
-
- if (c === '.' || c === '#' || c === '&') { return; }
-
- if (name = $(this.variable) || $(this.ruleProperty)) {
- // prefer to try to parse first if its a variable or we are compressing
- // but always fallback on the other one
- value = !tryAnonymous && (env.compress || (name.charAt(0) === '@')) ?
- ($(this.value) || $(this.anonymousValue)) :
- ($(this.anonymousValue) || $(this.value));
-
-
- important = $(this.important);
- if (name[name.length-1] === "+") {
- merge = true;
- name = name.substr(0, name.length - 1);
- }
-
- if (value && $(this.end)) {
- return new (tree.Rule)(name, value, important, merge, memo, env.currentFileInfo);
- } else {
- furthest = i;
- restore();
- if (value && !tryAnonymous) {
- return this.rule(true);
- }
- }
- }
- },
- anonymousValue: function () {
- var match;
- if (match = /^([^@+\/'"*`(;{}-]*);/.exec(chunks[j])) {
- i += match[0].length - 1;
- return new(tree.Anonymous)(match[1]);
- }
- },
-
- //
- // An @import directive
- //
- // @import "lib";
- //
- // Depending on our environemnt, importing is done differently:
- // In the browser, it's an XHR request, in Node, it would be a
- // file-system operation. The function used for importing is
- // stored in `import`, which we pass to the Import constructor.
- //
- "import": function () {
- var path, features, index = i;
-
- save();
-
- var dir = $(/^@import?\s+/);
-
- var options = (dir ? $(this.importOptions) : null) || {};
-
- if (dir && (path = $(this.entities.quoted) || $(this.entities.url))) {
- features = $(this.mediaFeatures);
- if ($(';')) {
- features = features && new(tree.Value)(features);
- return new(tree.Import)(path, features, options, index, env.currentFileInfo);
- }
- }
-
- restore();
- },
-
- importOptions: function() {
- var o, options = {}, optionName, value;
-
- // list of options, surrounded by parens
- if (! $('(')) { return null; }
- do {
- if (o = $(this.importOption)) {
- optionName = o;
- value = true;
- switch(optionName) {
- case "css":
- optionName = "less";
- value = false;
- break;
- case "once":
- optionName = "multiple";
- value = false;
- break;
- }
- options[optionName] = value;
- if (! $(',')) { break; }
- }
- } while (o);
- expect(')');
- return options;
- },
-
- importOption: function() {
- var opt = $(/^(less|css|multiple|once|inline|reference)/);
- if (opt) {
- return opt[1];
- }
- },
-
- mediaFeature: function () {
- var e, p, nodes = [];
-
- do {
- if (e = ($(this.entities.keyword) || $(this.entities.variable))) {
- nodes.push(e);
- } else if ($('(')) {
- p = $(this.property);
- e = $(this.value);
- if ($(')')) {
- if (p && e) {
- nodes.push(new(tree.Paren)(new(tree.Rule)(p, e, null, null, i, env.currentFileInfo, true)));
- } else if (e) {
- nodes.push(new(tree.Paren)(e));
- } else {
- return null;
- }
- } else { return null; }
- }
- } while (e);
-
- if (nodes.length > 0) {
- return new(tree.Expression)(nodes);
- }
- },
-
- mediaFeatures: function () {
- var e, features = [];
-
- do {
- if (e = $(this.mediaFeature)) {
- features.push(e);
- if (! $(',')) { break; }
- } else if (e = $(this.entities.variable)) {
- features.push(e);
- if (! $(',')) { break; }
- }
- } while (e);
-
- return features.length > 0 ? features : null;
- },
-
- media: function () {
- var features, rules, media, debugInfo;
-
- if (env.dumpLineNumbers) {
- debugInfo = getDebugInfo(i, input, env);
- }
-
- if ($(/^@media/)) {
- features = $(this.mediaFeatures);
-
- if (rules = $(this.block)) {
- media = new(tree.Media)(rules, features, i, env.currentFileInfo);
- if (env.dumpLineNumbers) {
- media.debugInfo = debugInfo;
- }
- return media;
- }
- }
- },
-
- //
- // A CSS Directive
- //
- // @charset "utf-8";
- //
- directive: function () {
- var name, value, rules, nonVendorSpecificName,
- hasBlock, hasIdentifier, hasExpression, identifier;
-
- if (input.charAt(i) !== '@') { return; }
-
- if (value = $(this['import']) || $(this.media)) {
- return value;
- }
-
- save();
-
- name = $(/^@[a-z-]+/);
-
- if (!name) { return; }
-
- nonVendorSpecificName = name;
- if (name.charAt(1) == '-' && name.indexOf('-', 2) > 0) {
- nonVendorSpecificName = "@" + name.slice(name.indexOf('-', 2) + 1);
- }
-
- switch(nonVendorSpecificName) {
- case "@font-face":
- hasBlock = true;
- break;
- case "@viewport":
- case "@top-left":
- case "@top-left-corner":
- case "@top-center":
- case "@top-right":
- case "@top-right-corner":
- case "@bottom-left":
- case "@bottom-left-corner":
- case "@bottom-center":
- case "@bottom-right":
- case "@bottom-right-corner":
- case "@left-top":
- case "@left-middle":
- case "@left-bottom":
- case "@right-top":
- case "@right-middle":
- case "@right-bottom":
- hasBlock = true;
- break;
- case "@host":
- case "@page":
- case "@document":
- case "@supports":
- case "@keyframes":
- hasBlock = true;
- hasIdentifier = true;
- break;
- case "@namespace":
- hasExpression = true;
- break;
- }
-
- if (hasIdentifier) {
- identifier = ($(/^[^{]+/) || '').trim();
- if (identifier) {
- name += " " + identifier;
- }
- }
-
- if (hasBlock)
- {
- if (rules = $(this.block)) {
- return new(tree.Directive)(name, rules, i, env.currentFileInfo);
- }
- } else {
- if ((value = hasExpression ? $(this.expression) : $(this.entity)) && $(';')) {
- var directive = new(tree.Directive)(name, value, i, env.currentFileInfo);
- if (env.dumpLineNumbers) {
- directive.debugInfo = getDebugInfo(i, input, env);
- }
- return directive;
- }
- }
-
- restore();
- },
-
- //
- // A Value is a comma-delimited list of Expressions
- //
- // font-family: Baskerville, Georgia, serif;
- //
- // In a Rule, a Value represents everything after the `:`,
- // and before the `;`.
- //
- value: function () {
- var e, expressions = [];
-
- while (e = $(this.expression)) {
- expressions.push(e);
- if (! $(',')) { break; }
- }
-
- if (expressions.length > 0) {
- return new(tree.Value)(expressions);
- }
- },
- important: function () {
- if (input.charAt(i) === '!') {
- return $(/^! *important/);
- }
- },
- sub: function () {
- var a, e;
-
- if ($('(')) {
- if (a = $(this.addition)) {
- e = new(tree.Expression)([a]);
- expect(')');
- e.parens = true;
- return e;
- }
- }
- },
- multiplication: function () {
- var m, a, op, operation, isSpaced;
- if (m = $(this.operand)) {
- isSpaced = isWhitespace(input.charAt(i - 1));
- while (!peek(/^\/[*\/]/) && (op = ($('/') || $('*')))) {
- if (a = $(this.operand)) {
- m.parensInOp = true;
- a.parensInOp = true;
- operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
- isSpaced = isWhitespace(input.charAt(i - 1));
- } else {
- break;
- }
- }
- return operation || m;
- }
- },
- addition: function () {
- var m, a, op, operation, isSpaced;
- if (m = $(this.multiplication)) {
- isSpaced = isWhitespace(input.charAt(i - 1));
- while ((op = $(/^[-+]\s+/) || (!isSpaced && ($('+') || $('-')))) &&
- (a = $(this.multiplication))) {
- m.parensInOp = true;
- a.parensInOp = true;
- operation = new(tree.Operation)(op, [operation || m, a], isSpaced);
- isSpaced = isWhitespace(input.charAt(i - 1));
- }
- return operation || m;
- }
- },
- conditions: function () {
- var a, b, index = i, condition;
-
- if (a = $(this.condition)) {
- while (peek(/^,\s*(not\s*)?\(/) && $(',') && (b = $(this.condition))) {
- condition = new(tree.Condition)('or', condition || a, b, index);
- }
- return condition || a;
- }
- },
- condition: function () {
- var a, b, c, op, index = i, negate = false;
-
- if ($(/^not/)) { negate = true; }
- expect('(');
- if (a = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
- if (op = $(/^(?:>=|<=|=<|[<=>])/)) {
- if (b = $(this.addition) || $(this.entities.keyword) || $(this.entities.quoted)) {
- c = new(tree.Condition)(op, a, b, index, negate);
- } else {
- error('expected expression');
- }
- } else {
- c = new(tree.Condition)('=', a, new(tree.Keyword)('true'), index, negate);
- }
- expect(')');
- return $(/^and/) ? new(tree.Condition)('and', c, $(this.condition)) : c;
- }
- },
-
- //
- // An operand is anything that can be part of an operation,
- // such as a Color, or a Variable
- //
- operand: function () {
- var negate, p = input.charAt(i + 1);
-
- if (input.charAt(i) === '-' && (p === '@' || p === '(')) { negate = $('-'); }
- var o = $(this.sub) || $(this.entities.dimension) ||
- $(this.entities.color) || $(this.entities.variable) ||
- $(this.entities.call);
-
- if (negate) {
- o.parensInOp = true;
- o = new(tree.Negative)(o);
- }
-
- return o;
- },
-
- //
- // Expressions either represent mathematical operations,
- // or white-space delimited Entities.
- //
- // 1px solid black
- // @var * 2
- //
- expression: function () {
- var e, delim, entities = [];
-
- while (e = $(this.addition) || $(this.entity)) {
- entities.push(e);
- // operations do not allow keyword "/" dimension (e.g. small/20px) so we support that here
- if (!peek(/^\/[\/*]/) && (delim = $('/'))) {
- entities.push(new(tree.Anonymous)(delim));
- }
- }
- if (entities.length > 0) {
- return new(tree.Expression)(entities);
- }
- },
- property: function () {
- var name;
-
- if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*:/)) {
- return name[1];
- }
- },
- ruleProperty: function () {
- var name;
-
- if (name = $(/^(\*?-?[_a-zA-Z0-9-]+)\s*(\+?)\s*:/)) {
- return name[1] + (name[2] || "");
- }
- }
- }
- };
-};
-
-
-(function (tree) {
-
-tree.functions = {
- rgb: function (r, g, b) {
- return this.rgba(r, g, b, 1.0);
- },
- rgba: function (r, g, b, a) {
- var rgb = [r, g, b].map(function (c) { return scaled(c, 256); });
- a = number(a);
- return new(tree.Color)(rgb, a);
- },
- hsl: function (h, s, l) {
- return this.hsla(h, s, l, 1.0);
- },
- hsla: function (h, s, l, a) {
- function hue(h) {
- h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
- if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; }
- else if (h * 2 < 1) { return m2; }
- else if (h * 3 < 2) { return m1 + (m2 - m1) * (2/3 - h) * 6; }
- else { return m1; }
- }
-
- h = (number(h) % 360) / 360;
- s = clamp(number(s)); l = clamp(number(l)); a = clamp(number(a));
-
- var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
- var m1 = l * 2 - m2;
-
- return this.rgba(hue(h + 1/3) * 255,
- hue(h) * 255,
- hue(h - 1/3) * 255,
- a);
- },
-
- hsv: function(h, s, v) {
- return this.hsva(h, s, v, 1.0);
- },
-
- hsva: function(h, s, v, a) {
- h = ((number(h) % 360) / 360) * 360;
- s = number(s); v = number(v); a = number(a);
-
- var i, f;
- i = Math.floor((h / 60) % 6);
- f = (h / 60) - i;
-
- var vs = [v,
- v * (1 - s),
- v * (1 - f * s),
- v * (1 - (1 - f) * s)];
- var perm = [[0, 3, 1],
- [2, 0, 1],
- [1, 0, 3],
- [1, 2, 0],
- [3, 1, 0],
- [0, 1, 2]];
-
- return this.rgba(vs[perm[i][0]] * 255,
- vs[perm[i][1]] * 255,
- vs[perm[i][2]] * 255,
- a);
- },
-
- hue: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSL().h));
- },
- saturation: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
- },
- lightness: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
- },
- hsvhue: function(color) {
- return new(tree.Dimension)(Math.round(color.toHSV().h));
- },
- hsvsaturation: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSV().s * 100), '%');
- },
- hsvvalue: function (color) {
- return new(tree.Dimension)(Math.round(color.toHSV().v * 100), '%');
- },
- red: function (color) {
- return new(tree.Dimension)(color.rgb[0]);
- },
- green: function (color) {
- return new(tree.Dimension)(color.rgb[1]);
- },
- blue: function (color) {
- return new(tree.Dimension)(color.rgb[2]);
- },
- alpha: function (color) {
- return new(tree.Dimension)(color.toHSL().a);
- },
- luma: function (color) {
- return new(tree.Dimension)(Math.round(color.luma() * color.alpha * 100), '%');
- },
- saturate: function (color, amount) {
- // filter: saturate(3.2);
- // should be kept as is, so check for color
- if (!color.rgb) {
- return null;
- }
- var hsl = color.toHSL();
-
- hsl.s += amount.value / 100;
- hsl.s = clamp(hsl.s);
- return hsla(hsl);
- },
- desaturate: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.s -= amount.value / 100;
- hsl.s = clamp(hsl.s);
- return hsla(hsl);
- },
- lighten: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.l += amount.value / 100;
- hsl.l = clamp(hsl.l);
- return hsla(hsl);
- },
- darken: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.l -= amount.value / 100;
- hsl.l = clamp(hsl.l);
- return hsla(hsl);
- },
- fadein: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.a += amount.value / 100;
- hsl.a = clamp(hsl.a);
- return hsla(hsl);
- },
- fadeout: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.a -= amount.value / 100;
- hsl.a = clamp(hsl.a);
- return hsla(hsl);
- },
- fade: function (color, amount) {
- var hsl = color.toHSL();
-
- hsl.a = amount.value / 100;
- hsl.a = clamp(hsl.a);
- return hsla(hsl);
- },
- spin: function (color, amount) {
- var hsl = color.toHSL();
- var hue = (hsl.h + amount.value) % 360;
-
- hsl.h = hue < 0 ? 360 + hue : hue;
-
- return hsla(hsl);
- },
- //
- // Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
- // http://sass-lang.com
- //
- mix: function (color1, color2, weight) {
- if (!weight) {
- weight = new(tree.Dimension)(50);
- }
- var p = weight.value / 100.0;
- var w = p * 2 - 1;
- var a = color1.toHSL().a - color2.toHSL().a;
-
- var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
- var w2 = 1 - w1;
-
- var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
- color1.rgb[1] * w1 + color2.rgb[1] * w2,
- color1.rgb[2] * w1 + color2.rgb[2] * w2];
-
- var alpha = color1.alpha * p + color2.alpha * (1 - p);
-
- return new(tree.Color)(rgb, alpha);
- },
- greyscale: function (color) {
- return this.desaturate(color, new(tree.Dimension)(100));
- },
- contrast: function (color, dark, light, threshold) {
- // filter: contrast(3.2);
- // should be kept as is, so check for color
- if (!color.rgb) {
- return null;
- }
- if (typeof light === 'undefined') {
- light = this.rgba(255, 255, 255, 1.0);
- }
- if (typeof dark === 'undefined') {
- dark = this.rgba(0, 0, 0, 1.0);
- }
- //Figure out which is actually light and dark!
- if (dark.luma() > light.luma()) {
- var t = light;
- light = dark;
- dark = t;
- }
- if (typeof threshold === 'undefined') {
- threshold = 0.43;
- } else {
- threshold = number(threshold);
- }
- if ((color.luma() * color.alpha) < threshold) {
- return light;
- } else {
- return dark;
- }
- },
- e: function (str) {
- return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
- },
- escape: function (str) {
- return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
- },
- '%': function (quoted /* arg, arg, ...*/) {
- var args = Array.prototype.slice.call(arguments, 1),
- str = quoted.value;
-
- for (var i = 0; i < args.length; i++) {
- /*jshint loopfunc:true */
- str = str.replace(/%[sda]/i, function(token) {
- var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
- return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
- });
- }
- str = str.replace(/%%/g, '%');
- return new(tree.Quoted)('"' + str + '"', str);
- },
- unit: function (val, unit) {
- if(!(val instanceof tree.Dimension)) {
- throw { type: "Argument", message: "the first argument to unit must be a number" + (val instanceof tree.Operation ? ". Have you forgotten parenthesis?" : "") };
- }
- return new(tree.Dimension)(val.value, unit ? unit.toCSS() : "");
- },
- convert: function (val, unit) {
- return val.convertTo(unit.value);
- },
- round: function (n, f) {
- var fraction = typeof(f) === "undefined" ? 0 : f.value;
- return this._math(function(num) { return num.toFixed(fraction); }, null, n);
- },
- pi: function () {
- return new(tree.Dimension)(Math.PI);
- },
- mod: function(a, b) {
- return new(tree.Dimension)(a.value % b.value, a.unit);
- },
- pow: function(x, y) {
- if (typeof x === "number" && typeof y === "number") {
- x = new(tree.Dimension)(x);
- y = new(tree.Dimension)(y);
- } else if (!(x instanceof tree.Dimension) || !(y instanceof tree.Dimension)) {
- throw { type: "Argument", message: "arguments must be numbers" };
- }
-
- return new(tree.Dimension)(Math.pow(x.value, y.value), x.unit);
- },
- _math: function (fn, unit, n) {
- if (n instanceof tree.Dimension) {
- /*jshint eqnull:true */
- return new(tree.Dimension)(fn(parseFloat(n.value)), unit == null ? n.unit : unit);
- } else if (typeof(n) === 'number') {
- return fn(n);
- } else {
- throw { type: "Argument", message: "argument must be a number" };
- }
- },
- _minmax: function (isMin, args) {
- args = Array.prototype.slice.call(args);
- switch(args.length) {
- case 0: throw { type: "Argument", message: "one or more arguments required" };
- case 1: return args[0];
- }
- var i, j, current, currentUnified, referenceUnified, unit,
- order = [], // elems only contains original argument values.
- values = {}; // key is the unit.toString() for unified tree.Dimension values,
- // value is the index into the order array.
- for (i = 0; i < args.length; i++) {
- current = args[i];
- if (!(current instanceof tree.Dimension)) {
- order.push(current);
- continue;
- }
- currentUnified = current.unify();
- unit = currentUnified.unit.toString();
- j = values[unit];
- if (j === undefined) {
- values[unit] = order.length;
- order.push(current);
- continue;
- }
- referenceUnified = order[j].unify();
- if ( isMin && currentUnified.value < referenceUnified.value ||
- !isMin && currentUnified.value > referenceUnified.value) {
- order[j] = current;
- }
- }
- if (order.length == 1) {
- return order[0];
- }
- args = order.map(function (a) { return a.toCSS(this.env); })
- .join(this.env.compress ? "," : ", ");
- return new(tree.Anonymous)((isMin ? "min" : "max") + "(" + args + ")");
- },
- min: function () {
- return this._minmax(true, arguments);
- },
- max: function () {
- return this._minmax(false, arguments);
- },
- argb: function (color) {
- return new(tree.Anonymous)(color.toARGB());
-
- },
- percentage: function (n) {
- return new(tree.Dimension)(n.value * 100, '%');
- },
- color: function (n) {
- if (n instanceof tree.Quoted) {
- var colorCandidate = n.value,
- returnColor;
- returnColor = tree.Color.fromKeyword(colorCandidate);
- if (returnColor) {
- return returnColor;
- }
- if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/.test(colorCandidate)) {
- return new(tree.Color)(colorCandidate.slice(1));
- }
- throw { type: "Argument", message: "argument must be a color keyword or 3/6 digit hex e.g. #FFF" };
- } else {
- throw { type: "Argument", message: "argument must be a string" };
- }
- },
- iscolor: function (n) {
- return this._isa(n, tree.Color);
- },
- isnumber: function (n) {
- return this._isa(n, tree.Dimension);
- },
- isstring: function (n) {
- return this._isa(n, tree.Quoted);
- },
- iskeyword: function (n) {
- return this._isa(n, tree.Keyword);
- },
- isurl: function (n) {
- return this._isa(n, tree.URL);
- },
- ispixel: function (n) {
- return this.isunit(n, 'px');
- },
- ispercentage: function (n) {
- return this.isunit(n, '%');
- },
- isem: function (n) {
- return this.isunit(n, 'em');
- },
- isunit: function (n, unit) {
- return (n instanceof tree.Dimension) && n.unit.is(unit.value || unit) ? tree.True : tree.False;
- },
- _isa: function (n, Type) {
- return (n instanceof Type) ? tree.True : tree.False;
- },
-
- /* Blending modes */
-
- multiply: function(color1, color2) {
- var r = color1.rgb[0] * color2.rgb[0] / 255;
- var g = color1.rgb[1] * color2.rgb[1] / 255;
- var b = color1.rgb[2] * color2.rgb[2] / 255;
- return this.rgb(r, g, b);
- },
- screen: function(color1, color2) {
- var r = 255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
- var g = 255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
- var b = 255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
- return this.rgb(r, g, b);
- },
- overlay: function(color1, color2) {
- var r = color1.rgb[0] < 128 ? 2 * color1.rgb[0] * color2.rgb[0] / 255 : 255 - 2 * (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255;
- var g = color1.rgb[1] < 128 ? 2 * color1.rgb[1] * color2.rgb[1] / 255 : 255 - 2 * (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255;
- var b = color1.rgb[2] < 128 ? 2 * color1.rgb[2] * color2.rgb[2] / 255 : 255 - 2 * (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255;
- return this.rgb(r, g, b);
- },
- softlight: function(color1, color2) {
- var t = color2.rgb[0] * color1.rgb[0] / 255;
- var r = t + color1.rgb[0] * (255 - (255 - color1.rgb[0]) * (255 - color2.rgb[0]) / 255 - t) / 255;
- t = color2.rgb[1] * color1.rgb[1] / 255;
- var g = t + color1.rgb[1] * (255 - (255 - color1.rgb[1]) * (255 - color2.rgb[1]) / 255 - t) / 255;
- t = color2.rgb[2] * color1.rgb[2] / 255;
- var b = t + color1.rgb[2] * (255 - (255 - color1.rgb[2]) * (255 - color2.rgb[2]) / 255 - t) / 255;
- return this.rgb(r, g, b);
- },
- hardlight: function(color1, color2) {
- var r = color2.rgb[0] < 128 ? 2 * color2.rgb[0] * color1.rgb[0] / 255 : 255 - 2 * (255 - color2.rgb[0]) * (255 - color1.rgb[0]) / 255;
- var g = color2.rgb[1] < 128 ? 2 * color2.rgb[1] * color1.rgb[1] / 255 : 255 - 2 * (255 - color2.rgb[1]) * (255 - color1.rgb[1]) / 255;
- var b = color2.rgb[2] < 128 ? 2 * color2.rgb[2] * color1.rgb[2] / 255 : 255 - 2 * (255 - color2.rgb[2]) * (255 - color1.rgb[2]) / 255;
- return this.rgb(r, g, b);
- },
- difference: function(color1, color2) {
- var r = Math.abs(color1.rgb[0] - color2.rgb[0]);
- var g = Math.abs(color1.rgb[1] - color2.rgb[1]);
- var b = Math.abs(color1.rgb[2] - color2.rgb[2]);
- return this.rgb(r, g, b);
- },
- exclusion: function(color1, color2) {
- var r = color1.rgb[0] + color2.rgb[0] * (255 - color1.rgb[0] - color1.rgb[0]) / 255;
- var g = color1.rgb[1] + color2.rgb[1] * (255 - color1.rgb[1] - color1.rgb[1]) / 255;
- var b = color1.rgb[2] + color2.rgb[2] * (255 - color1.rgb[2] - color1.rgb[2]) / 255;
- return this.rgb(r, g, b);
- },
- average: function(color1, color2) {
- var r = (color1.rgb[0] + color2.rgb[0]) / 2;
- var g = (color1.rgb[1] + color2.rgb[1]) / 2;
- var b = (color1.rgb[2] + color2.rgb[2]) / 2;
- return this.rgb(r, g, b);
- },
- negation: function(color1, color2) {
- var r = 255 - Math.abs(255 - color2.rgb[0] - color1.rgb[0]);
- var g = 255 - Math.abs(255 - color2.rgb[1] - color1.rgb[1]);
- var b = 255 - Math.abs(255 - color2.rgb[2] - color1.rgb[2]);
- return this.rgb(r, g, b);
- },
- tint: function(color, amount) {
- return this.mix(this.rgb(255,255,255), color, amount);
- },
- shade: function(color, amount) {
- return this.mix(this.rgb(0, 0, 0), color, amount);
- },
- extract: function(values, index) {
- index = index.value - 1; // (1-based index)
- // handle non-array values as an array of length 1
- // return 'undefined' if index is invalid
- return Array.isArray(values.value)
- ? values.value[index] : Array(values)[index];
- },
- length: function(values) {
- var n = Array.isArray(values.value) ? values.value.length : 1;
- return new tree.Dimension(n);
- },
-
- "data-uri": function(mimetypeNode, filePathNode) {
-
- if (typeof window !== 'undefined') {
- return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
- }
-
- var mimetype = mimetypeNode.value;
- var filePath = (filePathNode && filePathNode.value);
-
- var fs = require("fs"),
- path = require("path"),
- useBase64 = false;
-
- if (arguments.length < 2) {
- filePath = mimetype;
- }
-
- if (this.env.isPathRelative(filePath)) {
- if (this.currentFileInfo.relativeUrls) {
- filePath = path.join(this.currentFileInfo.currentDirectory, filePath);
- } else {
- filePath = path.join(this.currentFileInfo.entryPath, filePath);
- }
- }
-
- // detect the mimetype if not given
- if (arguments.length < 2) {
- var mime;
- try {
- mime = require('mime');
- } catch (ex) {
- mime = tree._mime;
- }
-
- mimetype = mime.lookup(filePath);
-
- // use base 64 unless it's an ASCII or UTF-8 format
- var charset = mime.charsets.lookup(mimetype);
- useBase64 = ['US-ASCII', 'UTF-8'].indexOf(charset) < 0;
- if (useBase64) { mimetype += ';base64'; }
- }
- else {
- useBase64 = /;base64$/.test(mimetype);
- }
-
- var buf = fs.readFileSync(filePath);
-
- // IE8 cannot handle a data-uri larger than 32KB. If this is exceeded
- // and the --ieCompat flag is enabled, return a normal url() instead.
- var DATA_URI_MAX_KB = 32,
- fileSizeInKB = parseInt((buf.length / 1024), 10);
- if (fileSizeInKB >= DATA_URI_MAX_KB) {
-
- if (this.env.ieCompat !== false) {
- if (!this.env.silent) {
- console.warn("Skipped data-uri embedding of %s because its size (%dKB) exceeds IE8-safe %dKB!", filePath, fileSizeInKB, DATA_URI_MAX_KB);
- }
-
- return new tree.URL(filePathNode || mimetypeNode, this.currentFileInfo).eval(this.env);
- }
- }
-
- buf = useBase64 ? buf.toString('base64')
- : encodeURIComponent(buf);
-
- var uri = "'data:" + mimetype + ',' + buf + "'";
- return new(tree.URL)(new(tree.Anonymous)(uri));
- },
-
- "svg-gradient": function(direction) {
-
- function throwArgumentDescriptor() {
- throw { type: "Argument", message: "svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]" };
- }
-
- if (arguments.length < 3) {
- throwArgumentDescriptor();
- }
- var stops = Array.prototype.slice.call(arguments, 1),
- gradientDirectionSvg,
- gradientType = "linear",
- rectangleDimension = 'x="0" y="0" width="1" height="1"',
- useBase64 = true,
- renderEnv = {compress: false},
- returner,
- directionValue = direction.toCSS(renderEnv),
- i, color, position, positionValue, alpha;
-
- switch (directionValue) {
- case "to bottom":
- gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"';
- break;
- case "to right":
- gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"';
- break;
- case "to bottom right":
- gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"';
- break;
- case "to top right":
- gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"';
- break;
- case "ellipse":
- case "ellipse at center":
- gradientType = "radial";
- gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"';
- rectangleDimension = 'x="-50" y="-50" width="101" height="101"';
- break;
- default:
- throw { type: "Argument", message: "svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'" };
- }
- returner = '<?xml version="1.0" ?>' +
- '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' +
- '<' + gradientType + 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' + gradientDirectionSvg + '>';
-
- for (i = 0; i < stops.length; i+= 1) {
- if (stops[i].value) {
- color = stops[i].value[0];
- position = stops[i].value[1];
- } else {
- color = stops[i];
- position = undefined;
- }
-
- if (!(color instanceof tree.Color) || (!((i === 0 || i+1 === stops.length) && position === undefined) && !(position instanceof tree.Dimension))) {
- throwArgumentDescriptor();
- }
- positionValue = position ? position.toCSS(renderEnv) : i === 0 ? "0%" : "100%";
- alpha = color.alpha;
- returner += '<stop offset="' + positionValue + '" stop-color="' + color.toRGB() + '"' + (alpha < 1 ? ' stop-opacity="' + alpha + '"' : '') + '/>';
- }
- returner += '</' + gradientType + 'Gradient>' +
- '<rect ' + rectangleDimension + ' fill="url(#gradient)" /></svg>';
-
- if (useBase64) {
- // only works in node, needs interface to what is supported in environment
- try {
- returner = new Buffer(returner).toString('base64');
- } catch(e) {
- useBase64 = false;
- }
- }
-
- returner = "'data:image/svg+xml" + (useBase64 ? ";base64" : "") + "," + returner + "'";
- return new(tree.URL)(new(tree.Anonymous)(returner));
- }
-};
-
-// these static methods are used as a fallback when the optional 'mime' dependency is missing
-tree._mime = {
- // this map is intentionally incomplete
- // if you want more, install 'mime' dep
- _types: {
- '.htm' : 'text/html',
- '.html': 'text/html',
- '.gif' : 'image/gif',
- '.jpg' : 'image/jpeg',
- '.jpeg': 'image/jpeg',
- '.png' : 'image/png'
- },
- lookup: function (filepath) {
- var ext = require('path').extname(filepath),
- type = tree._mime._types[ext];
- if (type === undefined) {
- throw new Error('Optional dependency "mime" is required for ' + ext);
- }
- return type;
- },
- charsets: {
- lookup: function (type) {
- // assumes all text types are UTF-8
- return type && (/^text\//).test(type) ? 'UTF-8' : '';
- }
- }
-};
-
-var mathFunctions = [{name:"ceil"}, {name:"floor"}, {name: "sqrt"}, {name:"abs"},
- {name:"tan", unit: ""}, {name:"sin", unit: ""}, {name:"cos", unit: ""},
- {name:"atan", unit: "rad"}, {name:"asin", unit: "rad"}, {name:"acos", unit: "rad"}],
- createMathFunction = function(name, unit) {
- return function(n) {
- /*jshint eqnull:true */
- if (unit != null) {
- n = n.unify();
- }
- return this._math(Math[name], unit, n);
- };
- };
-
-for(var i = 0; i < mathFunctions.length; i++) {
- tree.functions[mathFunctions[i].name] = createMathFunction(mathFunctions[i].name, mathFunctions[i].unit);
-}
-
-function hsla(color) {
- return tree.functions.hsla(color.h, color.s, color.l, color.a);
-}
-
-function scaled(n, size) {
- if (n instanceof tree.Dimension && n.unit.is('%')) {
- return parseFloat(n.value * size / 100);
- } else {
- return number(n);
- }
-}
-
-function number(n) {
- if (n instanceof tree.Dimension) {
- return parseFloat(n.unit.is('%') ? n.value / 100 : n.value);
- } else if (typeof(n) === 'number') {
- return n;
- } else {
- throw {
- error: "RuntimeError",
- message: "color functions take numbers as parameters"
- };
- }
-}
-
-function clamp(val) {
- return Math.min(1, Math.max(0, val));
-}
-
-tree.functionCall = function(env, currentFileInfo) {
- this.env = env;
- this.currentFileInfo = currentFileInfo;
-};
-
-tree.functionCall.prototype = tree.functions;
-
-})(require('./tree'));
-
-(function (tree) {
- tree.colors = {
- 'aliceblue':'#f0f8ff',
- 'antiquewhite':'#faebd7',
- 'aqua':'#00ffff',
- 'aquamarine':'#7fffd4',
- 'azure':'#f0ffff',
- 'beige':'#f5f5dc',
- 'bisque':'#ffe4c4',
- 'black':'#000000',
- 'blanchedalmond':'#ffebcd',
- 'blue':'#0000ff',
- 'blueviolet':'#8a2be2',
- 'brown':'#a52a2a',
- 'burlywood':'#deb887',
- 'cadetblue':'#5f9ea0',
- 'chartreuse':'#7fff00',
- 'chocolate':'#d2691e',
- 'coral':'#ff7f50',
- 'cornflowerblue':'#6495ed',
- 'cornsilk':'#fff8dc',
- 'crimson':'#dc143c',
- 'cyan':'#00ffff',
- 'darkblue':'#00008b',
- 'darkcyan':'#008b8b',
- 'darkgoldenrod':'#b8860b',
- 'darkgray':'#a9a9a9',
- 'darkgrey':'#a9a9a9',
- 'darkgreen':'#006400',
- 'darkkhaki':'#bdb76b',
- 'darkmagenta':'#8b008b',
- 'darkolivegreen':'#556b2f',
- 'darkorange':'#ff8c00',
- 'darkorchid':'#9932cc',
- 'darkred':'#8b0000',
- 'darksalmon':'#e9967a',
- 'darkseagreen':'#8fbc8f',
- 'darkslateblue':'#483d8b',
- 'darkslategray':'#2f4f4f',
- 'darkslategrey':'#2f4f4f',
- 'darkturquoise':'#00ced1',
- 'darkviolet':'#9400d3',
- 'deeppink':'#ff1493',
- 'deepskyblue':'#00bfff',
- 'dimgray':'#696969',
- 'dimgrey':'#696969',
- 'dodgerblue':'#1e90ff',
- 'firebrick':'#b22222',
- 'floralwhite':'#fffaf0',
- 'forestgreen':'#228b22',
- 'fuchsia':'#ff00ff',
- 'gainsboro':'#dcdcdc',
- 'ghostwhite':'#f8f8ff',
- 'gold':'#ffd700',
- 'goldenrod':'#daa520',
- 'gray':'#808080',
- 'grey':'#808080',
- 'green':'#008000',
- 'greenyellow':'#adff2f',
- 'honeydew':'#f0fff0',
- 'hotpink':'#ff69b4',
- 'indianred':'#cd5c5c',
- 'indigo':'#4b0082',
- 'ivory':'#fffff0',
- 'khaki':'#f0e68c',
- 'lavender':'#e6e6fa',
- 'lavenderblush':'#fff0f5',
- 'lawngreen':'#7cfc00',
- 'lemonchiffon':'#fffacd',
- 'lightblue':'#add8e6',
- 'lightcoral':'#f08080',
- 'lightcyan':'#e0ffff',
- 'lightgoldenrodyellow':'#fafad2',
- 'lightgray':'#d3d3d3',
- 'lightgrey':'#d3d3d3',
- 'lightgreen':'#90ee90',
- 'lightpink':'#ffb6c1',
- 'lightsalmon':'#ffa07a',
- 'lightseagreen':'#20b2aa',
- 'lightskyblue':'#87cefa',
- 'lightslategray':'#778899',
- 'lightslategrey':'#778899',
- 'lightsteelblue':'#b0c4de',
- 'lightyellow':'#ffffe0',
- 'lime':'#00ff00',
- 'limegreen':'#32cd32',
- 'linen':'#faf0e6',
- 'magenta':'#ff00ff',
- 'maroon':'#800000',
- 'mediumaquamarine':'#66cdaa',
- 'mediumblue':'#0000cd',
- 'mediumorchid':'#ba55d3',
- 'mediumpurple':'#9370d8',
- 'mediumseagreen':'#3cb371',
- 'mediumslateblue':'#7b68ee',
- 'mediumspringgreen':'#00fa9a',
- 'mediumturquoise':'#48d1cc',
- 'mediumvioletred':'#c71585',
- 'midnightblue':'#191970',
- 'mintcream':'#f5fffa',
- 'mistyrose':'#ffe4e1',
- 'moccasin':'#ffe4b5',
- 'navajowhite':'#ffdead',
- 'navy':'#000080',
- 'oldlace':'#fdf5e6',
- 'olive':'#808000',
- 'olivedrab':'#6b8e23',
- 'orange':'#ffa500',
- 'orangered':'#ff4500',
- 'orchid':'#da70d6',
- 'palegoldenrod':'#eee8aa',
- 'palegreen':'#98fb98',
- 'paleturquoise':'#afeeee',
- 'palevioletred':'#d87093',
- 'papayawhip':'#ffefd5',
- 'peachpuff':'#ffdab9',
- 'peru':'#cd853f',
- 'pink':'#ffc0cb',
- 'plum':'#dda0dd',
- 'powderblue':'#b0e0e6',
- 'purple':'#800080',
- 'red':'#ff0000',
- 'rosybrown':'#bc8f8f',
- 'royalblue':'#4169e1',
- 'saddlebrown':'#8b4513',
- 'salmon':'#fa8072',
- 'sandybrown':'#f4a460',
- 'seagreen':'#2e8b57',
- 'seashell':'#fff5ee',
- 'sienna':'#a0522d',
- 'silver':'#c0c0c0',
- 'skyblue':'#87ceeb',
- 'slateblue':'#6a5acd',
- 'slategray':'#708090',
- 'slategrey':'#708090',
- 'snow':'#fffafa',
- 'springgreen':'#00ff7f',
- 'steelblue':'#4682b4',
- 'tan':'#d2b48c',
- 'teal':'#008080',
- 'thistle':'#d8bfd8',
- 'tomato':'#ff6347',
- 'turquoise':'#40e0d0',
- 'violet':'#ee82ee',
- 'wheat':'#f5deb3',
- 'white':'#ffffff',
- 'whitesmoke':'#f5f5f5',
- 'yellow':'#ffff00',
- 'yellowgreen':'#9acd32'
- };
-})(require('./tree'));
-
-(function (tree) {
-
-tree.debugInfo = function(env, ctx, lineSeperator) {
- var result="";
- if (env.dumpLineNumbers && !env.compress) {
- switch(env.dumpLineNumbers) {
- case 'comments':
- result = tree.debugInfo.asComment(ctx);
- break;
- case 'mediaquery':
- result = tree.debugInfo.asMediaQuery(ctx);
- break;
- case 'all':
- result = tree.debugInfo.asComment(ctx) + (lineSeperator || "") + tree.debugInfo.asMediaQuery(ctx);
- break;
- }
- }
- return result;
-};
-
-tree.debugInfo.asComment = function(ctx) {
- return '/* line ' + ctx.debugInfo.lineNumber + ', ' + ctx.debugInfo.fileName + ' */\n';
-};
-
-tree.debugInfo.asMediaQuery = function(ctx) {
- return '@media -sass-debug-info{filename{font-family:' +
- ('file://' + ctx.debugInfo.fileName).replace(/([.:/\\])/g, function (a) {
- if (a == '\\') {
- a = '\/';
- }
- return '\\' + a;
- }) +
- '}line{font-family:\\00003' + ctx.debugInfo.lineNumber + '}}\n';
-};
-
-tree.find = function (obj, fun) {
- for (var i = 0, r; i < obj.length; i++) {
- if (r = fun.call(obj, obj[i])) { return r; }
- }
- return null;
-};
-
-tree.jsify = function (obj) {
- if (Array.isArray(obj.value) && (obj.value.length > 1)) {
- return '[' + obj.value.map(function (v) { return v.toCSS(false); }).join(', ') + ']';
- } else {
- return obj.toCSS(false);
- }
-};
-
-tree.toCSS = function (env) {
- var strs = [];
- this.genCSS(env, {
- add: function(chunk, fileInfo, index) {
- strs.push(chunk);
- },
- isEmpty: function () {
- return strs.length === 0;
- }
- });
- return strs.join('');
-};
-
-tree.outputRuleset = function (env, output, rules) {
- output.add((env.compress ? '{' : ' {\n'));
- env.tabLevel = (env.tabLevel || 0) + 1;
- var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
- tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" ");
- for(var i = 0; i < rules.length; i++) {
- output.add(tabRuleStr);
- rules[i].genCSS(env, output);
- output.add(env.compress ? '' : '\n');
- }
- env.tabLevel--;
- output.add(tabSetStr + "}");
-};
-
-})(require('./tree'));
-
-(function (tree) {
-
-tree.Alpha = function (val) {
- this.value = val;
-};
-tree.Alpha.prototype = {
- type: "Alpha",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- if (this.value.eval) { return new tree.Alpha(this.value.eval(env)); }
- return this;
- },
- genCSS: function (env, output) {
- output.add("alpha(opacity=");
-
- if (this.value.genCSS) {
- this.value.genCSS(env, output);
- } else {
- output.add(this.value);
- }
-
- output.add(")");
- },
- toCSS: tree.toCSS
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Anonymous = function (string, index, currentFileInfo, mapLines) {
- this.value = string.value || string;
- this.index = index;
- this.mapLines = mapLines;
- this.currentFileInfo = currentFileInfo;
-};
-tree.Anonymous.prototype = {
- type: "Anonymous",
- eval: function () { return this; },
- compare: function (x) {
- if (!x.toCSS) {
- return -1;
- }
-
- var left = this.toCSS(),
- right = x.toCSS();
-
- if (left === right) {
- return 0;
- }
-
- return left < right ? -1 : 1;
- },
- genCSS: function (env, output) {
- output.add(this.value, this.currentFileInfo, this.index, this.mapLines);
- },
- toCSS: tree.toCSS
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Assignment = function (key, val) {
- this.key = key;
- this.value = val;
-};
-tree.Assignment.prototype = {
- type: "Assignment",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- if (this.value.eval) {
- return new(tree.Assignment)(this.key, this.value.eval(env));
- }
- return this;
- },
- genCSS: function (env, output) {
- output.add(this.key + '=');
- if (this.value.genCSS) {
- this.value.genCSS(env, output);
- } else {
- output.add(this.value);
- }
- },
- toCSS: tree.toCSS
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-//
-// A function call node.
-//
-tree.Call = function (name, args, index, currentFileInfo) {
- this.name = name;
- this.args = args;
- this.index = index;
- this.currentFileInfo = currentFileInfo;
-};
-tree.Call.prototype = {
- type: "Call",
- accept: function (visitor) {
- this.args = visitor.visit(this.args);
- },
- //
- // When evaluating a function call,
- // we either find the function in `tree.functions` [1],
- // in which case we call it, passing the evaluated arguments,
- // if this returns null or we cannot find the function, we
- // simply print it out as it appeared originally [2].
- //
- // The *functions.js* file contains the built-in functions.
- //
- // The reason why we evaluate the arguments, is in the case where
- // we try to pass a variable to a function, like: `saturate(@color)`.
- // The function should receive the value, not the variable.
- //
- eval: function (env) {
- var args = this.args.map(function (a) { return a.eval(env); }),
- nameLC = this.name.toLowerCase(),
- result, func;
-
- if (nameLC in tree.functions) { // 1.
- try {
- func = new tree.functionCall(env, this.currentFileInfo);
- result = func[nameLC].apply(func, args);
- /*jshint eqnull:true */
- if (result != null) {
- return result;
- }
- } catch (e) {
- throw { type: e.type || "Runtime",
- message: "error evaluating function `" + this.name + "`" +
- (e.message ? ': ' + e.message : ''),
- index: this.index, filename: this.currentFileInfo.filename };
- }
- }
-
- return new tree.Call(this.name, args, this.index, this.currentFileInfo);
- },
-
- genCSS: function (env, output) {
- output.add(this.name + "(", this.currentFileInfo, this.index);
-
- for(var i = 0; i < this.args.length; i++) {
- this.args[i].genCSS(env, output);
- if (i + 1 < this.args.length) {
- output.add(", ");
- }
- }
-
- output.add(")");
- },
-
- toCSS: tree.toCSS
-};
-
-})(require('../tree'));
-
-(function (tree) {
-//
-// RGB Colors - #ff0014, #eee
-//
-tree.Color = function (rgb, a) {
- //
- // The end goal here, is to parse the arguments
- // into an integer triplet, such as `128, 255, 0`
- //
- // This facilitates operations and conversions.
- //
- if (Array.isArray(rgb)) {
- this.rgb = rgb;
- } else if (rgb.length == 6) {
- this.rgb = rgb.match(/.{2}/g).map(function (c) {
- return parseInt(c, 16);
- });
- } else {
- this.rgb = rgb.split('').map(function (c) {
- return parseInt(c + c, 16);
- });
- }
- this.alpha = typeof(a) === 'number' ? a : 1;
-};
-
-var transparentKeyword = "transparent";
-
-tree.Color.prototype = {
- type: "Color",
- eval: function () { return this; },
- luma: function () { return (0.2126 * this.rgb[0] / 255) + (0.7152 * this.rgb[1] / 255) + (0.0722 * this.rgb[2] / 255); },
-
- genCSS: function (env, output) {
- output.add(this.toCSS(env));
- },
- toCSS: function (env, doNotCompress) {
- var compress = env && env.compress && !doNotCompress;
-
- // If we have some transparency, the only way to represent it
- // is via `rgba`. Otherwise, we use the hex representation,
- // which has better compatibility with older browsers.
- // Values are capped between `0` and `255`, rounded and zero-padded.
- if (this.alpha < 1.0) {
- if (this.alpha === 0 && this.isTransparentKeyword) {
- return transparentKeyword;
- }
- return "rgba(" + this.rgb.map(function (c) {
- return Math.round(c);
- }).concat(this.alpha).join(',' + (compress ? '' : ' ')) + ")";
- } else {
- var color = this.toRGB();
-
- if (compress) {
- var splitcolor = color.split('');
-
- // Convert color to short format
- if (splitcolor[1] === splitcolor[2] && splitcolor[3] === splitcolor[4] && splitcolor[5] === splitcolor[6]) {
- color = '#' + splitcolor[1] + splitcolor[3] + splitcolor[5];
- }
- }
-
- return color;
- }
- },
-
- //
- // Operations have to be done per-channel, if not,
- // channels will spill onto each other. Once we have
- // our result, in the form of an integer triplet,
- // we create a new Color node to hold the result.
- //
- operate: function (env, op, other) {
- var result = [];
-
- if (! (other instanceof tree.Color)) {
- other = other.toColor();
- }
-
- for (var c = 0; c < 3; c++) {
- result[c] = tree.operate(env, op, this.rgb[c], other.rgb[c]);
- }
- return new(tree.Color)(result, this.alpha + other.alpha);
- },
-
- toRGB: function () {
- return '#' + this.rgb.map(function (i) {
- i = Math.round(i);
- i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
- return i.length === 1 ? '0' + i : i;
- }).join('');
- },
-
- toHSL: function () {
- var r = this.rgb[0] / 255,
- g = this.rgb[1] / 255,
- b = this.rgb[2] / 255,
- a = this.alpha;
-
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
- var h, s, l = (max + min) / 2, d = max - min;
-
- if (max === min) {
- h = s = 0;
- } else {
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
-
- switch (max) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h /= 6;
- }
- return { h: h * 360, s: s, l: l, a: a };
- },
- //Adapted from http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
- toHSV: function () {
- var r = this.rgb[0] / 255,
- g = this.rgb[1] / 255,
- b = this.rgb[2] / 255,
- a = this.alpha;
-
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
- var h, s, v = max;
-
- var d = max - min;
- if (max === 0) {
- s = 0;
- } else {
- s = d / max;
- }
-
- if (max === min) {
- h = 0;
- } else {
- switch(max){
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h /= 6;
- }
- return { h: h * 360, s: s, v: v, a: a };
- },
- toARGB: function () {
- var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
- return '#' + argb.map(function (i) {
- i = Math.round(i);
- i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
- return i.length === 1 ? '0' + i : i;
- }).join('');
- },
- compare: function (x) {
- if (!x.rgb) {
- return -1;
- }
-
- return (x.rgb[0] === this.rgb[0] &&
- x.rgb[1] === this.rgb[1] &&
- x.rgb[2] === this.rgb[2] &&
- x.alpha === this.alpha) ? 0 : -1;
- }
-};
-
-tree.Color.fromKeyword = function(keyword) {
- if (tree.colors.hasOwnProperty(keyword)) {
- // detect named color
- return new(tree.Color)(tree.colors[keyword].slice(1));
- }
- if (keyword === transparentKeyword) {
- var transparent = new(tree.Color)([0, 0, 0], 0);
- transparent.isTransparentKeyword = true;
- return transparent;
- }
-};
-
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Comment = function (value, silent, index, currentFileInfo) {
- this.value = value;
- this.silent = !!silent;
- this.currentFileInfo = currentFileInfo;
-};
-tree.Comment.prototype = {
- type: "Comment",
- genCSS: function (env, output) {
- if (this.debugInfo) {
- output.add(tree.debugInfo(env, this), this.currentFileInfo, this.index);
- }
- output.add(this.value.trim()); //TODO shouldn't need to trim, we shouldn't grab the \n
- },
- toCSS: tree.toCSS,
- isSilent: function(env) {
- var isReference = (this.currentFileInfo && this.currentFileInfo.reference && !this.isReferenced),
- isCompressed = env.compress && !this.value.match(/^\/\*!/);
- return this.silent || isReference || isCompressed;
- },
- eval: function () { return this; },
- markReferenced: function () {
- this.isReferenced = true;
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Condition = function (op, l, r, i, negate) {
- this.op = op.trim();
- this.lvalue = l;
- this.rvalue = r;
- this.index = i;
- this.negate = negate;
-};
-tree.Condition.prototype = {
- type: "Condition",
- accept: function (visitor) {
- this.lvalue = visitor.visit(this.lvalue);
- this.rvalue = visitor.visit(this.rvalue);
- },
- eval: function (env) {
- var a = this.lvalue.eval(env),
- b = this.rvalue.eval(env);
-
- var i = this.index, result;
-
- result = (function (op) {
- switch (op) {
- case 'and':
- return a && b;
- case 'or':
- return a || b;
- default:
- if (a.compare) {
- result = a.compare(b);
- } else if (b.compare) {
- result = b.compare(a);
- } else {
- throw { type: "Type",
- message: "Unable to perform comparison",
- index: i };
- }
- switch (result) {
- case -1: return op === '<' || op === '=<' || op === '<=';
- case 0: return op === '=' || op === '>=' || op === '=<' || op === '<=';
- case 1: return op === '>' || op === '>=';
- }
- }
- })(this.op);
- return this.negate ? !result : result;
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-//
-// A number with a unit
-//
-tree.Dimension = function (value, unit) {
- this.value = parseFloat(value);
- this.unit = (unit && unit instanceof tree.Unit) ? unit :
- new(tree.Unit)(unit ? [unit] : undefined);
-};
-
-tree.Dimension.prototype = {
- type: "Dimension",
- accept: function (visitor) {
- this.unit = visitor.visit(this.unit);
- },
- eval: function (env) {
- return this;
- },
- toColor: function () {
- return new(tree.Color)([this.value, this.value, this.value]);
- },
- genCSS: function (env, output) {
- if ((env && env.strictUnits) && !this.unit.isSingular()) {
- throw new Error("Multiple units in dimension. Correct the units or use the unit function. Bad unit: "+this.unit.toString());
- }
-
- var value = this.value,
- strValue = String(value);
-
- if (value !== 0 && value < 0.000001 && value > -0.000001) {
- // would be output 1e-6 etc.
- strValue = value.toFixed(20).replace(/0+$/, "");
- }
-
- if (env && env.compress) {
- // Zero values doesn't need a unit
- if (value === 0 && this.unit.isLength()) {
- output.add(strValue);
- return;
- }
-
- // Float values doesn't need a leading zero
- if (value > 0 && value < 1) {
- strValue = (strValue).substr(1);
- }
- }
-
- output.add(strValue);
- this.unit.genCSS(env, output);
- },
- toCSS: tree.toCSS,
-
- // In an operation between two Dimensions,
- // we default to the first Dimension's unit,
- // so `1px + 2` will yield `3px`.
- operate: function (env, op, other) {
- /*jshint noempty:false */
- var value = tree.operate(env, op, this.value, other.value),
- unit = this.unit.clone();
-
- if (op === '+' || op === '-') {
- if (unit.numerator.length === 0 && unit.denominator.length === 0) {
- unit.numerator = other.unit.numerator.slice(0);
- unit.denominator = other.unit.denominator.slice(0);
- } else if (other.unit.numerator.length === 0 && unit.denominator.length === 0) {
- // do nothing
- } else {
- other = other.convertTo(this.unit.usedUnits());
-
- if(env.strictUnits && other.unit.toString() !== unit.toString()) {
- throw new Error("Incompatible units. Change the units or use the unit function. Bad units: '" + unit.toString() +
- "' and '" + other.unit.toString() + "'.");
- }
-
- value = tree.operate(env, op, this.value, other.value);
- }
- } else if (op === '*') {
- unit.numerator = unit.numerator.concat(other.unit.numerator).sort();
- unit.denominator = unit.denominator.concat(other.unit.denominator).sort();
- unit.cancel();
- } else if (op === '/') {
- unit.numerator = unit.numerator.concat(other.unit.denominator).sort();
- unit.denominator = unit.denominator.concat(other.unit.numerator).sort();
- unit.cancel();
- }
- return new(tree.Dimension)(value, unit);
- },
-
- compare: function (other) {
- if (other instanceof tree.Dimension) {
- var a = this.unify(), b = other.unify(),
- aValue = a.value, bValue = b.value;
-
- if (bValue > aValue) {
- return -1;
- } else if (bValue < aValue) {
- return 1;
- } else {
- if (!b.unit.isEmpty() && a.unit.compare(b.unit) !== 0) {
- return -1;
- }
- return 0;
- }
- } else {
- return -1;
- }
- },
-
- unify: function () {
- return this.convertTo({ length: 'm', duration: 's', angle: 'rad' });
- },
-
- convertTo: function (conversions) {
- var value = this.value, unit = this.unit.clone(),
- i, groupName, group, targetUnit, derivedConversions = {}, applyUnit;
-
- if (typeof conversions === 'string') {
- for(i in tree.UnitConversions) {
- if (tree.UnitConversions[i].hasOwnProperty(conversions)) {
- derivedConversions = {};
- derivedConversions[i] = conversions;
- }
- }
- conversions = derivedConversions;
- }
- applyUnit = function (atomicUnit, denominator) {
- /*jshint loopfunc:true */
- if (group.hasOwnProperty(atomicUnit)) {
- if (denominator) {
- value = value / (group[atomicUnit] / group[targetUnit]);
- } else {
- value = value * (group[atomicUnit] / group[targetUnit]);
- }
-
- return targetUnit;
- }
-
- return atomicUnit;
- };
-
- for (groupName in conversions) {
- if (conversions.hasOwnProperty(groupName)) {
- targetUnit = conversions[groupName];
- group = tree.UnitConversions[groupName];
-
- unit.map(applyUnit);
- }
- }
-
- unit.cancel();
-
- return new(tree.Dimension)(value, unit);
- }
-};
-
-// http://www.w3.org/TR/css3-values/#absolute-lengths
-tree.UnitConversions = {
- length: {
- 'm': 1,
- 'cm': 0.01,
- 'mm': 0.001,
- 'in': 0.0254,
- 'pt': 0.0254 / 72,
- 'pc': 0.0254 / 72 * 12
- },
- duration: {
- 's': 1,
- 'ms': 0.001
- },
- angle: {
- 'rad': 1/(2*Math.PI),
- 'deg': 1/360,
- 'grad': 1/400,
- 'turn': 1
- }
-};
-
-tree.Unit = function (numerator, denominator, backupUnit) {
- this.numerator = numerator ? numerator.slice(0).sort() : [];
- this.denominator = denominator ? denominator.slice(0).sort() : [];
- this.backupUnit = backupUnit;
-};
-
-tree.Unit.prototype = {
- type: "Unit",
- clone: function () {
- return new tree.Unit(this.numerator.slice(0), this.denominator.slice(0), this.backupUnit);
- },
- genCSS: function (env, output) {
- if (this.numerator.length >= 1) {
- output.add(this.numerator[0]);
- } else
- if (this.denominator.length >= 1) {
- output.add(this.denominator[0]);
- } else
- if ((!env || !env.strictUnits) && this.backupUnit) {
- output.add(this.backupUnit);
- }
- },
- toCSS: tree.toCSS,
-
- toString: function () {
- var i, returnStr = this.numerator.join("*");
- for (i = 0; i < this.denominator.length; i++) {
- returnStr += "/" + this.denominator[i];
- }
- return returnStr;
- },
-
- compare: function (other) {
- return this.is(other.toString()) ? 0 : -1;
- },
-
- is: function (unitString) {
- return this.toString() === unitString;
- },
-
- isLength: function () {
- return Boolean(this.toCSS().match(/px|em|%|in|cm|mm|pc|pt|ex/));
- },
-
- isEmpty: function () {
- return this.numerator.length === 0 && this.denominator.length === 0;
- },
-
- isSingular: function() {
- return this.numerator.length <= 1 && this.denominator.length === 0;
- },
-
- map: function(callback) {
- var i;
-
- for (i = 0; i < this.numerator.length; i++) {
- this.numerator[i] = callback(this.numerator[i], false);
- }
-
- for (i = 0; i < this.denominator.length; i++) {
- this.denominator[i] = callback(this.denominator[i], true);
- }
- },
-
- usedUnits: function() {
- var group, result = {}, mapUnit;
-
- mapUnit = function (atomicUnit) {
- /*jshint loopfunc:true */
- if (group.hasOwnProperty(atomicUnit) && !result[groupName]) {
- result[groupName] = atomicUnit;
- }
-
- return atomicUnit;
- };
-
- for (var groupName in tree.UnitConversions) {
- if (tree.UnitConversions.hasOwnProperty(groupName)) {
- group = tree.UnitConversions[groupName];
-
- this.map(mapUnit);
- }
- }
-
- return result;
- },
-
- cancel: function () {
- var counter = {}, atomicUnit, i, backup;
-
- for (i = 0; i < this.numerator.length; i++) {
- atomicUnit = this.numerator[i];
- if (!backup) {
- backup = atomicUnit;
- }
- counter[atomicUnit] = (counter[atomicUnit] || 0) + 1;
- }
-
- for (i = 0; i < this.denominator.length; i++) {
- atomicUnit = this.denominator[i];
- if (!backup) {
- backup = atomicUnit;
- }
- counter[atomicUnit] = (counter[atomicUnit] || 0) - 1;
- }
-
- this.numerator = [];
- this.denominator = [];
-
- for (atomicUnit in counter) {
- if (counter.hasOwnProperty(atomicUnit)) {
- var count = counter[atomicUnit];
-
- if (count > 0) {
- for (i = 0; i < count; i++) {
- this.numerator.push(atomicUnit);
- }
- } else if (count < 0) {
- for (i = 0; i < -count; i++) {
- this.denominator.push(atomicUnit);
- }
- }
- }
- }
-
- if (this.numerator.length === 0 && this.denominator.length === 0 && backup) {
- this.backupUnit = backup;
- }
-
- this.numerator.sort();
- this.denominator.sort();
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Directive = function (name, value, index, currentFileInfo) {
- this.name = name;
-
- if (Array.isArray(value)) {
- this.rules = [new(tree.Ruleset)([], value)];
- this.rules[0].allowImports = true;
- } else {
- this.value = value;
- }
- this.currentFileInfo = currentFileInfo;
-
-};
-tree.Directive.prototype = {
- type: "Directive",
- accept: function (visitor) {
- this.rules = visitor.visit(this.rules);
- this.value = visitor.visit(this.value);
- },
- genCSS: function (env, output) {
- output.add(this.name, this.currentFileInfo, this.index);
- if (this.rules) {
- tree.outputRuleset(env, output, this.rules);
- } else {
- output.add(' ');
- this.value.genCSS(env, output);
- output.add(';');
- }
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- var evaldDirective = this;
- if (this.rules) {
- env.frames.unshift(this);
- evaldDirective = new(tree.Directive)(this.name, null, this.index, this.currentFileInfo);
- evaldDirective.rules = [this.rules[0].eval(env)];
- evaldDirective.rules[0].root = true;
- env.frames.shift();
- }
- return evaldDirective;
- },
- variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
- find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
- rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
- markReferenced: function () {
- var i, rules;
- this.isReferenced = true;
- if (this.rules) {
- rules = this.rules[0].rules;
- for (i = 0; i < rules.length; i++) {
- if (rules[i].markReferenced) {
- rules[i].markReferenced();
- }
- }
- }
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Element = function (combinator, value, index, currentFileInfo) {
- this.combinator = combinator instanceof tree.Combinator ?
- combinator : new(tree.Combinator)(combinator);
-
- if (typeof(value) === 'string') {
- this.value = value.trim();
- } else if (value) {
- this.value = value;
- } else {
- this.value = "";
- }
- this.index = index;
- this.currentFileInfo = currentFileInfo;
-};
-tree.Element.prototype = {
- type: "Element",
- accept: function (visitor) {
- this.combinator = visitor.visit(this.combinator);
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- return new(tree.Element)(this.combinator,
- this.value.eval ? this.value.eval(env) : this.value,
- this.index,
- this.currentFileInfo);
- },
- genCSS: function (env, output) {
- output.add(this.toCSS(env), this.currentFileInfo, this.index);
- },
- toCSS: function (env) {
- var value = (this.value.toCSS ? this.value.toCSS(env) : this.value);
- if (value === '' && this.combinator.value.charAt(0) === '&') {
- return '';
- } else {
- return this.combinator.toCSS(env || {}) + value;
- }
- }
-};
-
-tree.Attribute = function (key, op, value) {
- this.key = key;
- this.op = op;
- this.value = value;
-};
-tree.Attribute.prototype = {
- type: "Attribute",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- return new(tree.Attribute)(this.key.eval ? this.key.eval(env) : this.key,
- this.op, (this.value && this.value.eval) ? this.value.eval(env) : this.value);
- },
- genCSS: function (env, output) {
- output.add(this.toCSS(env));
- },
- toCSS: function (env) {
- var value = this.key.toCSS ? this.key.toCSS(env) : this.key;
-
- if (this.op) {
- value += this.op;
- value += (this.value.toCSS ? this.value.toCSS(env) : this.value);
- }
-
- return '[' + value + ']';
- }
-};
-
-tree.Combinator = function (value) {
- if (value === ' ') {
- this.value = ' ';
- } else {
- this.value = value ? value.trim() : "";
- }
-};
-tree.Combinator.prototype = {
- type: "Combinator",
- _outputMap: {
- '' : '',
- ' ' : ' ',
- ':' : ' :',
- '+' : ' + ',
- '~' : ' ~ ',
- '>' : ' > ',
- '|' : '|'
- },
- _outputMapCompressed: {
- '' : '',
- ' ' : ' ',
- ':' : ' :',
- '+' : '+',
- '~' : '~',
- '>' : '>',
- '|' : '|'
- },
- genCSS: function (env, output) {
- output.add((env.compress ? this._outputMapCompressed : this._outputMap)[this.value]);
- },
- toCSS: tree.toCSS
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Expression = function (value) { this.value = value; };
-tree.Expression.prototype = {
- type: "Expression",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- var returnValue,
- inParenthesis = this.parens && !this.parensInOp,
- doubleParen = false;
- if (inParenthesis) {
- env.inParenthesis();
- }
- if (this.value.length > 1) {
- returnValue = new(tree.Expression)(this.value.map(function (e) {
- return e.eval(env);
- }));
- } else if (this.value.length === 1) {
- if (this.value[0].parens && !this.value[0].parensInOp) {
- doubleParen = true;
- }
- returnValue = this.value[0].eval(env);
- } else {
- returnValue = this;
- }
- if (inParenthesis) {
- env.outOfParenthesis();
- }
- if (this.parens && this.parensInOp && !(env.isMathOn()) && !doubleParen) {
- returnValue = new(tree.Paren)(returnValue);
- }
- return returnValue;
- },
- genCSS: function (env, output) {
- for(var i = 0; i < this.value.length; i++) {
- this.value[i].genCSS(env, output);
- if (i + 1 < this.value.length) {
- output.add(" ");
- }
- }
- },
- toCSS: tree.toCSS,
- throwAwayComments: function () {
- this.value = this.value.filter(function(v) {
- return !(v instanceof tree.Comment);
- });
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Extend = function Extend(selector, option, index) {
- this.selector = selector;
- this.option = option;
- this.index = index;
-
- switch(option) {
- case "all":
- this.allowBefore = true;
- this.allowAfter = true;
- break;
- default:
- this.allowBefore = false;
- this.allowAfter = false;
- break;
- }
-};
-
-tree.Extend.prototype = {
- type: "Extend",
- accept: function (visitor) {
- this.selector = visitor.visit(this.selector);
- },
- eval: function (env) {
- return new(tree.Extend)(this.selector.eval(env), this.option, this.index);
- },
- clone: function (env) {
- return new(tree.Extend)(this.selector, this.option, this.index);
- },
- findSelfSelectors: function (selectors) {
- var selfElements = [],
- i,
- selectorElements;
-
- for(i = 0; i < selectors.length; i++) {
- selectorElements = selectors[i].elements;
- // duplicate the logic in genCSS function inside the selector node.
- // future TODO - move both logics into the selector joiner visitor
- if (i > 0 && selectorElements.length && selectorElements[0].combinator.value === "") {
- selectorElements[0].combinator.value = ' ';
- }
- selfElements = selfElements.concat(selectors[i].elements);
- }
-
- this.selfSelectors = [{ elements: selfElements }];
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-//
-// CSS @import node
-//
-// The general strategy here is that we don't want to wait
-// for the parsing to be completed, before we start importing
-// the file. That's because in the context of a browser,
-// most of the time will be spent waiting for the server to respond.
-//
-// On creation, we push the import path to our import queue, though
-// `import,push`, we also pass it a callback, which it'll call once
-// the file has been fetched, and parsed.
-//
-tree.Import = function (path, features, options, index, currentFileInfo) {
- this.options = options;
- this.index = index;
- this.path = path;
- this.features = features;
- this.currentFileInfo = currentFileInfo;
-
- if (this.options.less !== undefined || this.options.inline) {
- this.css = !this.options.less || this.options.inline;
- } else {
- var pathValue = this.getPath();
- if (pathValue && /css([\?;].*)?$/.test(pathValue)) {
- this.css = true;
- }
- }
-};
-
-//
-// The actual import node doesn't return anything, when converted to CSS.
-// The reason is that it's used at the evaluation stage, so that the rules
-// it imports can be treated like any other rules.
-//
-// In `eval`, we make sure all Import nodes get evaluated, recursively, so
-// we end up with a flat structure, which can easily be imported in the parent
-// ruleset.
-//
-tree.Import.prototype = {
- type: "Import",
- accept: function (visitor) {
- this.features = visitor.visit(this.features);
- this.path = visitor.visit(this.path);
- if (!this.options.inline) {
- this.root = visitor.visit(this.root);
- }
- },
- genCSS: function (env, output) {
- if (this.css) {
- output.add("@import ", this.currentFileInfo, this.index);
- this.path.genCSS(env, output);
- if (this.features) {
- output.add(" ");
- this.features.genCSS(env, output);
- }
- output.add(';');
- }
- },
- toCSS: tree.toCSS,
- getPath: function () {
- if (this.path instanceof tree.Quoted) {
- var path = this.path.value;
- return (this.css !== undefined || /(\.[a-z]*$)|([\?;].*)$/.test(path)) ? path : path + '.less';
- } else if (this.path instanceof tree.URL) {
- return this.path.value.value;
- }
- return null;
- },
- evalForImport: function (env) {
- return new(tree.Import)(this.path.eval(env), this.features, this.options, this.index, this.currentFileInfo);
- },
- evalPath: function (env) {
- var path = this.path.eval(env);
- var rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
-
- if (!(path instanceof tree.URL)) {
- if (rootpath) {
- var pathValue = path.value;
- // Add the base path if the import is relative
- if (pathValue && env.isPathRelative(pathValue)) {
- path.value = rootpath + pathValue;
- }
- }
- path.value = env.normalizePath(path.value);
- }
-
- return path;
- },
- eval: function (env) {
- var ruleset, features = this.features && this.features.eval(env);
-
- if (this.skip) { return []; }
-
- if (this.options.inline) {
- //todo needs to reference css file not import
- var contents = new(tree.Anonymous)(this.root, 0, {filename: this.importedFilename}, true);
- return this.features ? new(tree.Media)([contents], this.features.value) : [contents];
- } else if (this.css) {
- var newImport = new(tree.Import)(this.evalPath(env), features, this.options, this.index);
- if (!newImport.css && this.error) {
- throw this.error;
- }
- return newImport;
- } else {
- ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
-
- ruleset.evalImports(env);
-
- return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
- }
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.JavaScript = function (string, index, escaped) {
- this.escaped = escaped;
- this.expression = string;
- this.index = index;
-};
-tree.JavaScript.prototype = {
- type: "JavaScript",
- eval: function (env) {
- var result,
- that = this,
- context = {};
-
- var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
- return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
- });
-
- try {
- expression = new(Function)('return (' + expression + ')');
- } catch (e) {
- throw { message: "JavaScript evaluation error: " + e.message + " from `" + expression + "`" ,
- index: this.index };
- }
-
- for (var k in env.frames[0].variables()) {
- /*jshint loopfunc:true */
- context[k.slice(1)] = {
- value: env.frames[0].variables()[k].value,
- toJS: function () {
- return this.value.eval(env).toCSS();
- }
- };
- }
-
- try {
- result = expression.call(context);
- } catch (e) {
- throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
- index: this.index };
- }
- if (typeof(result) === 'string') {
- return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
- } else if (Array.isArray(result)) {
- return new(tree.Anonymous)(result.join(', '));
- } else {
- return new(tree.Anonymous)(result);
- }
- }
-};
-
-})(require('../tree'));
-
-
-(function (tree) {
-
-tree.Keyword = function (value) { this.value = value; };
-tree.Keyword.prototype = {
- type: "Keyword",
- eval: function () { return this; },
- genCSS: function (env, output) {
- output.add(this.value);
- },
- toCSS: tree.toCSS,
- compare: function (other) {
- if (other instanceof tree.Keyword) {
- return other.value === this.value ? 0 : 1;
- } else {
- return -1;
- }
- }
-};
-
-tree.True = new(tree.Keyword)('true');
-tree.False = new(tree.Keyword)('false');
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Media = function (value, features, index, currentFileInfo) {
- this.index = index;
- this.currentFileInfo = currentFileInfo;
-
- var selectors = this.emptySelectors();
-
- this.features = new(tree.Value)(features);
- this.rules = [new(tree.Ruleset)(selectors, value)];
- this.rules[0].allowImports = true;
-};
-tree.Media.prototype = {
- type: "Media",
- accept: function (visitor) {
- this.features = visitor.visit(this.features);
- this.rules = visitor.visit(this.rules);
- },
- genCSS: function (env, output) {
- output.add('@media ', this.currentFileInfo, this.index);
- this.features.genCSS(env, output);
- tree.outputRuleset(env, output, this.rules);
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- if (!env.mediaBlocks) {
- env.mediaBlocks = [];
- env.mediaPath = [];
- }
-
- var media = new(tree.Media)([], [], this.index, this.currentFileInfo);
- if(this.debugInfo) {
- this.rules[0].debugInfo = this.debugInfo;
- media.debugInfo = this.debugInfo;
- }
- var strictMathBypass = false;
- if (!env.strictMath) {
- strictMathBypass = true;
- env.strictMath = true;
- }
- try {
- media.features = this.features.eval(env);
- }
- finally {
- if (strictMathBypass) {
- env.strictMath = false;
- }
- }
-
- env.mediaPath.push(media);
- env.mediaBlocks.push(media);
-
- env.frames.unshift(this.rules[0]);
- media.rules = [this.rules[0].eval(env)];
- env.frames.shift();
-
- env.mediaPath.pop();
-
- return env.mediaPath.length === 0 ? media.evalTop(env) :
- media.evalNested(env);
- },
- variable: function (name) { return tree.Ruleset.prototype.variable.call(this.rules[0], name); },
- find: function () { return tree.Ruleset.prototype.find.apply(this.rules[0], arguments); },
- rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.rules[0]); },
- emptySelectors: function() {
- var el = new(tree.Element)('', '&', this.index, this.currentFileInfo);
- return [new(tree.Selector)([el], null, null, this.index, this.currentFileInfo)];
- },
- markReferenced: function () {
- var i, rules = this.rules[0].rules;
- this.isReferenced = true;
- for (i = 0; i < rules.length; i++) {
- if (rules[i].markReferenced) {
- rules[i].markReferenced();
- }
- }
- },
-
- evalTop: function (env) {
- var result = this;
-
- // Render all dependent Media blocks.
- if (env.mediaBlocks.length > 1) {
- var selectors = this.emptySelectors();
- result = new(tree.Ruleset)(selectors, env.mediaBlocks);
- result.multiMedia = true;
- }
-
- delete env.mediaBlocks;
- delete env.mediaPath;
-
- return result;
- },
- evalNested: function (env) {
- var i, value,
- path = env.mediaPath.concat([this]);
-
- // Extract the media-query conditions separated with `,` (OR).
- for (i = 0; i < path.length; i++) {
- value = path[i].features instanceof tree.Value ?
- path[i].features.value : path[i].features;
- path[i] = Array.isArray(value) ? value : [value];
- }
-
- // Trace all permutations to generate the resulting media-query.
- //
- // (a, b and c) with nested (d, e) ->
- // a and d
- // a and e
- // b and c and d
- // b and c and e
- this.features = new(tree.Value)(this.permute(path).map(function (path) {
- path = path.map(function (fragment) {
- return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
- });
-
- for(i = path.length - 1; i > 0; i--) {
- path.splice(i, 0, new(tree.Anonymous)("and"));
- }
-
- return new(tree.Expression)(path);
- }));
-
- // Fake a tree-node that doesn't output anything.
- return new(tree.Ruleset)([], []);
- },
- permute: function (arr) {
- if (arr.length === 0) {
- return [];
- } else if (arr.length === 1) {
- return arr[0];
- } else {
- var result = [];
- var rest = this.permute(arr.slice(1));
- for (var i = 0; i < rest.length; i++) {
- for (var j = 0; j < arr[0].length; j++) {
- result.push([arr[0][j]].concat(rest[i]));
- }
- }
- return result;
- }
- },
- bubbleSelectors: function (selectors) {
- this.rules = [new(tree.Ruleset)(selectors.slice(0), [this.rules[0]])];
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.mixin = {};
-tree.mixin.Call = function (elements, args, index, currentFileInfo, important) {
- this.selector = new(tree.Selector)(elements);
- this.arguments = args;
- this.index = index;
- this.currentFileInfo = currentFileInfo;
- this.important = important;
-};
-tree.mixin.Call.prototype = {
- type: "MixinCall",
- accept: function (visitor) {
- this.selector = visitor.visit(this.selector);
- this.arguments = visitor.visit(this.arguments);
- },
- eval: function (env) {
- var mixins, mixin, args, rules = [], match = false, i, m, f, isRecursive, isOneFound, rule;
-
- args = this.arguments && this.arguments.map(function (a) {
- return { name: a.name, value: a.value.eval(env) };
- });
-
- for (i = 0; i < env.frames.length; i++) {
- if ((mixins = env.frames[i].find(this.selector)).length > 0) {
- isOneFound = true;
- for (m = 0; m < mixins.length; m++) {
- mixin = mixins[m];
- isRecursive = false;
- for(f = 0; f < env.frames.length; f++) {
- if ((!(mixin instanceof tree.mixin.Definition)) && mixin === (env.frames[f].originalRuleset || env.frames[f])) {
- isRecursive = true;
- break;
- }
- }
- if (isRecursive) {
- continue;
- }
- if (mixin.matchArgs(args, env)) {
- if (!mixin.matchCondition || mixin.matchCondition(args, env)) {
- try {
- if (!(mixin instanceof tree.mixin.Definition)) {
- mixin = new tree.mixin.Definition("", [], mixin.rules, null, false);
- mixin.originalRuleset = mixins[m].originalRuleset || mixins[m];
- }
- //if (this.important) {
- // isImportant = env.isImportant;
- // env.isImportant = true;
- //}
- Array.prototype.push.apply(
- rules, mixin.eval(env, args, this.important).rules);
- //if (this.important) {
- // env.isImportant = isImportant;
- //}
- } catch (e) {
- throw { message: e.message, index: this.index, filename: this.currentFileInfo.filename, stack: e.stack };
- }
- }
- match = true;
- }
- }
- if (match) {
- if (!this.currentFileInfo || !this.currentFileInfo.reference) {
- for (i = 0; i < rules.length; i++) {
- rule = rules[i];
- if (rule.markReferenced) {
- rule.markReferenced();
- }
- }
- }
- return rules;
- }
- }
- }
- if (isOneFound) {
- throw { type: 'Runtime',
- message: 'No matching definition was found for `' +
- this.selector.toCSS().trim() + '(' +
- (args ? args.map(function (a) {
- var argValue = "";
- if (a.name) {
- argValue += a.name + ":";
- }
- if (a.value.toCSS) {
- argValue += a.value.toCSS();
- } else {
- argValue += "???";
- }
- return argValue;
- }).join(', ') : "") + ")`",
- index: this.index, filename: this.currentFileInfo.filename };
- } else {
- throw { type: 'Name',
- message: this.selector.toCSS().trim() + " is undefined",
- index: this.index, filename: this.currentFileInfo.filename };
- }
- }
-};
-
-tree.mixin.Definition = function (name, params, rules, condition, variadic) {
- this.name = name;
- this.selectors = [new(tree.Selector)([new(tree.Element)(null, name, this.index, this.currentFileInfo)])];
- this.params = params;
- this.condition = condition;
- this.variadic = variadic;
- this.arity = params.length;
- this.rules = rules;
- this._lookups = {};
- this.required = params.reduce(function (count, p) {
- if (!p.name || (p.name && !p.value)) { return count + 1; }
- else { return count; }
- }, 0);
- this.parent = tree.Ruleset.prototype;
- this.frames = [];
-};
-tree.mixin.Definition.prototype = {
- type: "MixinDefinition",
- accept: function (visitor) {
- this.params = visitor.visit(this.params);
- this.rules = visitor.visit(this.rules);
- this.condition = visitor.visit(this.condition);
- },
- variable: function (name) { return this.parent.variable.call(this, name); },
- variables: function () { return this.parent.variables.call(this); },
- find: function () { return this.parent.find.apply(this, arguments); },
- rulesets: function () { return this.parent.rulesets.apply(this); },
-
- evalParams: function (env, mixinEnv, args, evaldArguments) {
- /*jshint boss:true */
- var frame = new(tree.Ruleset)(null, []),
- varargs, arg,
- params = this.params.slice(0),
- i, j, val, name, isNamedFound, argIndex;
-
- mixinEnv = new tree.evalEnv(mixinEnv, [frame].concat(mixinEnv.frames));
-
- if (args) {
- args = args.slice(0);
-
- for(i = 0; i < args.length; i++) {
- arg = args[i];
- if (name = (arg && arg.name)) {
- isNamedFound = false;
- for(j = 0; j < params.length; j++) {
- if (!evaldArguments[j] && name === params[j].name) {
- evaldArguments[j] = arg.value.eval(env);
- frame.rules.unshift(new(tree.Rule)(name, arg.value.eval(env)));
- isNamedFound = true;
- break;
- }
- }
- if (isNamedFound) {
- args.splice(i, 1);
- i--;
- continue;
- } else {
- throw { type: 'Runtime', message: "Named argument for " + this.name +
- ' ' + args[i].name + ' not found' };
- }
- }
- }
- }
- argIndex = 0;
- for (i = 0; i < params.length; i++) {
- if (evaldArguments[i]) { continue; }
-
- arg = args && args[argIndex];
-
- if (name = params[i].name) {
- if (params[i].variadic && args) {
- varargs = [];
- for (j = argIndex; j < args.length; j++) {
- varargs.push(args[j].value.eval(env));
- }
- frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
- } else {
- val = arg && arg.value;
- if (val) {
- val = val.eval(env);
- } else if (params[i].value) {
- val = params[i].value.eval(mixinEnv);
- frame.resetCache();
- } else {
- throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
- ' (' + args.length + ' for ' + this.arity + ')' };
- }
-
- frame.rules.unshift(new(tree.Rule)(name, val));
- evaldArguments[i] = val;
- }
- }
-
- if (params[i].variadic && args) {
- for (j = argIndex; j < args.length; j++) {
- evaldArguments[j] = args[j].value.eval(env);
- }
- }
- argIndex++;
- }
-
- return frame;
- },
- eval: function (env, args, important) {
- var _arguments = [],
- mixinFrames = this.frames.concat(env.frames),
- frame = this.evalParams(env, new(tree.evalEnv)(env, mixinFrames), args, _arguments),
- rules, ruleset;
-
- frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
-
- rules = this.rules.slice(0);
-
- ruleset = new(tree.Ruleset)(null, rules);
- ruleset.originalRuleset = this;
- ruleset = ruleset.eval(new(tree.evalEnv)(env, [this, frame].concat(mixinFrames)));
- if (important) {
- ruleset = this.parent.makeImportant.apply(ruleset);
- }
- return ruleset;
- },
- matchCondition: function (args, env) {
- if (this.condition && !this.condition.eval(
- new(tree.evalEnv)(env,
- [this.evalParams(env, new(tree.evalEnv)(env, this.frames.concat(env.frames)), args, [])] // the parameter variables
- .concat(this.frames) // the parent namespace/mixin frames
- .concat(env.frames)))) { // the current environment frames
- return false;
- }
- return true;
- },
- matchArgs: function (args, env) {
- var argsLength = (args && args.length) || 0, len;
-
- if (! this.variadic) {
- if (argsLength < this.required) { return false; }
- if (argsLength > this.params.length) { return false; }
- } else {
- if (argsLength < (this.required - 1)) { return false; }
- }
-
- len = Math.min(argsLength, this.arity);
-
- for (var i = 0; i < len; i++) {
- if (!this.params[i].name && !this.params[i].variadic) {
- if (args[i].value.eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
- return false;
- }
- }
- }
- return true;
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Negative = function (node) {
- this.value = node;
-};
-tree.Negative.prototype = {
- type: "Negative",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- genCSS: function (env, output) {
- output.add('-');
- this.value.genCSS(env, output);
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- if (env.isMathOn()) {
- return (new(tree.Operation)('*', [new(tree.Dimension)(-1), this.value])).eval(env);
- }
- return new(tree.Negative)(this.value.eval(env));
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Operation = function (op, operands, isSpaced) {
- this.op = op.trim();
- this.operands = operands;
- this.isSpaced = isSpaced;
-};
-tree.Operation.prototype = {
- type: "Operation",
- accept: function (visitor) {
- this.operands = visitor.visit(this.operands);
- },
- eval: function (env) {
- var a = this.operands[0].eval(env),
- b = this.operands[1].eval(env),
- temp;
-
- if (env.isMathOn()) {
- if (a instanceof tree.Dimension && b instanceof tree.Color) {
- if (this.op === '*' || this.op === '+') {
- temp = b, b = a, a = temp;
- } else {
- throw { type: "Operation",
- message: "Can't substract or divide a color from a number" };
- }
- }
- if (!a.operate) {
- throw { type: "Operation",
- message: "Operation on an invalid type" };
- }
-
- return a.operate(env, this.op, b);
- } else {
- return new(tree.Operation)(this.op, [a, b], this.isSpaced);
- }
- },
- genCSS: function (env, output) {
- this.operands[0].genCSS(env, output);
- if (this.isSpaced) {
- output.add(" ");
- }
- output.add(this.op);
- if (this.isSpaced) {
- output.add(" ");
- }
- this.operands[1].genCSS(env, output);
- },
- toCSS: tree.toCSS
-};
-
-tree.operate = function (env, op, a, b) {
- switch (op) {
- case '+': return a + b;
- case '-': return a - b;
- case '*': return a * b;
- case '/': return a / b;
- }
-};
-
-})(require('../tree'));
-
-
-(function (tree) {
-
-tree.Paren = function (node) {
- this.value = node;
-};
-tree.Paren.prototype = {
- type: "Paren",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- genCSS: function (env, output) {
- output.add('(');
- this.value.genCSS(env, output);
- output.add(')');
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- return new(tree.Paren)(this.value.eval(env));
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Quoted = function (str, content, escaped, index, currentFileInfo) {
- this.escaped = escaped;
- this.value = content || '';
- this.quote = str.charAt(0);
- this.index = index;
- this.currentFileInfo = currentFileInfo;
-};
-tree.Quoted.prototype = {
- type: "Quoted",
- genCSS: function (env, output) {
- if (!this.escaped) {
- output.add(this.quote, this.currentFileInfo, this.index);
- }
- output.add(this.value);
- if (!this.escaped) {
- output.add(this.quote);
- }
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- var that = this;
- var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
- return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
- }).replace(/@\{([\w-]+)\}/g, function (_, name) {
- var v = new(tree.Variable)('@' + name, that.index, that.currentFileInfo).eval(env, true);
- return (v instanceof tree.Quoted) ? v.value : v.toCSS();
- });
- return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index, this.currentFileInfo);
- },
- compare: function (x) {
- if (!x.toCSS) {
- return -1;
- }
-
- var left = this.toCSS(),
- right = x.toCSS();
-
- if (left === right) {
- return 0;
- }
-
- return left < right ? -1 : 1;
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Rule = function (name, value, important, merge, index, currentFileInfo, inline) {
- this.name = name;
- this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
- this.important = important ? ' ' + important.trim() : '';
- this.merge = merge;
- this.index = index;
- this.currentFileInfo = currentFileInfo;
- this.inline = inline || false;
- this.variable = (name.charAt(0) === '@');
-};
-
-tree.Rule.prototype = {
- type: "Rule",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- genCSS: function (env, output) {
- output.add(this.name + (env.compress ? ':' : ': '), this.currentFileInfo, this.index);
- try {
- this.value.genCSS(env, output);
- }
- catch(e) {
- e.index = this.index;
- e.filename = this.currentFileInfo.filename;
- throw e;
- }
- output.add(this.important + ((this.inline || (env.lastRule && env.compress)) ? "" : ";"), this.currentFileInfo, this.index);
- },
- toCSS: tree.toCSS,
- eval: function (env) {
- var strictMathBypass = false;
- if (this.name === "font" && !env.strictMath) {
- strictMathBypass = true;
- env.strictMath = true;
- }
- try {
- return new(tree.Rule)(this.name,
- this.value.eval(env),
- this.important,
- this.merge,
- this.index, this.currentFileInfo, this.inline);
- }
- finally {
- if (strictMathBypass) {
- env.strictMath = false;
- }
- }
- },
- makeImportant: function () {
- return new(tree.Rule)(this.name,
- this.value,
- "!important",
- this.merge,
- this.index, this.currentFileInfo, this.inline);
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Ruleset = function (selectors, rules, strictImports) {
- this.selectors = selectors;
- this.rules = rules;
- this._lookups = {};
- this.strictImports = strictImports;
-};
-tree.Ruleset.prototype = {
- type: "Ruleset",
- accept: function (visitor) {
- if (this.paths) {
- for(var i = 0; i < this.paths.length; i++) {
- this.paths[i] = visitor.visit(this.paths[i]);
- }
- } else {
- this.selectors = visitor.visit(this.selectors);
- }
- this.rules = visitor.visit(this.rules);
- },
- eval: function (env) {
- var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env); });
- var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
- var rules;
- var rule;
- var i;
-
- ruleset.originalRuleset = this;
- ruleset.root = this.root;
- ruleset.firstRoot = this.firstRoot;
- ruleset.allowImports = this.allowImports;
-
- if(this.debugInfo) {
- ruleset.debugInfo = this.debugInfo;
- }
-
- // push the current ruleset to the frames stack
- env.frames.unshift(ruleset);
-
- // currrent selectors
- if (!env.selectors) {
- env.selectors = [];
- }
- env.selectors.unshift(this.selectors);
-
- // Evaluate imports
- if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
- ruleset.evalImports(env);
- }
-
- // Store the frames around mixin definitions,
- // so they can be evaluated like closures when the time comes.
- for (i = 0; i < ruleset.rules.length; i++) {
- if (ruleset.rules[i] instanceof tree.mixin.Definition) {
- ruleset.rules[i].frames = env.frames.slice(0);
- }
- }
-
- var mediaBlockCount = (env.mediaBlocks && env.mediaBlocks.length) || 0;
-
- // Evaluate mixin calls.
- for (i = 0; i < ruleset.rules.length; i++) {
- if (ruleset.rules[i] instanceof tree.mixin.Call) {
- /*jshint loopfunc:true */
- rules = ruleset.rules[i].eval(env).filter(function(r) {
- if ((r instanceof tree.Rule) && r.variable) {
- // do not pollute the scope if the variable is
- // already there. consider returning false here
- // but we need a way to "return" variable from mixins
- return !(ruleset.variable(r.name));
- }
- return true;
- });
- ruleset.rules.splice.apply(ruleset.rules, [i, 1].concat(rules));
- i += rules.length-1;
- ruleset.resetCache();
- }
- }
-
- // Evaluate everything else
- for (i = 0; i < ruleset.rules.length; i++) {
- rule = ruleset.rules[i];
-
- if (! (rule instanceof tree.mixin.Definition)) {
- ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
- }
- }
-
- // Pop the stack
- env.frames.shift();
- env.selectors.shift();
-
- if (env.mediaBlocks) {
- for (i = mediaBlockCount; i < env.mediaBlocks.length; i++) {
- env.mediaBlocks[i].bubbleSelectors(selectors);
- }
- }
-
- return ruleset;
- },
- evalImports: function(env) {
- var i, rules;
- for (i = 0; i < this.rules.length; i++) {
- if (this.rules[i] instanceof tree.Import) {
- rules = this.rules[i].eval(env);
- if (typeof rules.length === "number") {
- this.rules.splice.apply(this.rules, [i, 1].concat(rules));
- i+= rules.length-1;
- } else {
- this.rules.splice(i, 1, rules);
- }
- this.resetCache();
- }
- }
- },
- makeImportant: function() {
- return new tree.Ruleset(this.selectors, this.rules.map(function (r) {
- if (r.makeImportant) {
- return r.makeImportant();
- } else {
- return r;
- }
- }), this.strictImports);
- },
- matchArgs: function (args) {
- return !args || args.length === 0;
- },
- matchCondition: function (args, env) {
- var lastSelector = this.selectors[this.selectors.length-1];
- if (lastSelector.condition &&
- !lastSelector.condition.eval(
- new(tree.evalEnv)(env,
- env.frames))) {
- return false;
- }
- return true;
- },
- resetCache: function () {
- this._rulesets = null;
- this._variables = null;
- this._lookups = {};
- },
- variables: function () {
- if (this._variables) { return this._variables; }
- else {
- return this._variables = this.rules.reduce(function (hash, r) {
- if (r instanceof tree.Rule && r.variable === true) {
- hash[r.name] = r;
- }
- return hash;
- }, {});
- }
- },
- variable: function (name) {
- return this.variables()[name];
- },
- rulesets: function () {
- return this.rules.filter(function (r) {
- return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
- });
- },
- find: function (selector, self) {
- self = self || this;
- var rules = [], match,
- key = selector.toCSS();
-
- if (key in this._lookups) { return this._lookups[key]; }
-
- this.rulesets().forEach(function (rule) {
- if (rule !== self) {
- for (var j = 0; j < rule.selectors.length; j++) {
- if (match = selector.match(rule.selectors[j])) {
- if (selector.elements.length > match) {
- Array.prototype.push.apply(rules, rule.find(
- new(tree.Selector)(selector.elements.slice(match)), self));
- } else {
- rules.push(rule);
- }
- break;
- }
- }
- }
- });
- return this._lookups[key] = rules;
- },
- genCSS: function (env, output) {
- var i, j,
- ruleNodes = [],
- rulesetNodes = [],
- debugInfo, // Line number debugging
- rule,
- firstRuleset = true,
- path;
-
- env.tabLevel = (env.tabLevel || 0);
-
- if (!this.root) {
- env.tabLevel++;
- }
-
- var tabRuleStr = env.compress ? '' : Array(env.tabLevel + 1).join(" "),
- tabSetStr = env.compress ? '' : Array(env.tabLevel).join(" ");
-
- for (i = 0; i < this.rules.length; i++) {
- rule = this.rules[i];
- if (rule.rules || (rule instanceof tree.Media) || rule instanceof tree.Directive || (this.root && rule instanceof tree.Comment)) {
- rulesetNodes.push(rule);
- } else {
- ruleNodes.push(rule);
- }
- }
-
- // If this is the root node, we don't render
- // a selector, or {}.
- if (!this.root) {
- debugInfo = tree.debugInfo(env, this, tabSetStr);
-
- if (debugInfo) {
- output.add(debugInfo);
- output.add(tabSetStr);
- }
-
- for(i = 0; i < this.paths.length; i++) {
- path = this.paths[i];
- env.firstSelector = true;
- for(j = 0; j < path.length; j++) {
- path[j].genCSS(env, output);
- env.firstSelector = false;
- }
- if (i + 1 < this.paths.length) {
- output.add(env.compress ? ',' : (',\n' + tabSetStr));
- }
- }
-
- output.add((env.compress ? '{' : ' {\n') + tabRuleStr);
- }
-
- // Compile rules and rulesets
- for (i = 0; i < ruleNodes.length; i++) {
- rule = ruleNodes[i];
-
- // @page{ directive ends up with root elements inside it, a mix of rules and rulesets
- // In this instance we do not know whether it is the last property
- if (i + 1 === ruleNodes.length && (!this.root || rulesetNodes.length === 0 || this.firstRoot)) {
- env.lastRule = true;
- }
-
- if (rule.genCSS) {
- rule.genCSS(env, output);
- } else if (rule.value) {
- output.add(rule.value.toString());
- }
-
- if (!env.lastRule) {
- output.add(env.compress ? '' : ('\n' + tabRuleStr));
- } else {
- env.lastRule = false;
- }
- }
-
- if (!this.root) {
- output.add((env.compress ? '}' : '\n' + tabSetStr + '}'));
- env.tabLevel--;
- }
-
- for (i = 0; i < rulesetNodes.length; i++) {
- if (ruleNodes.length && firstRuleset) {
- output.add((env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr));
- }
- if (!firstRuleset) {
- output.add((env.compress ? "" : "\n") + (this.root ? tabRuleStr : tabSetStr));
- }
- firstRuleset = false;
- rulesetNodes[i].genCSS(env, output);
- }
-
- if (!output.isEmpty() && !env.compress && this.firstRoot) {
- output.add('\n');
- }
- },
-
- toCSS: tree.toCSS,
-
- markReferenced: function () {
- for (var s = 0; s < this.selectors.length; s++) {
- this.selectors[s].markReferenced();
- }
- },
-
- joinSelectors: function (paths, context, selectors) {
- for (var s = 0; s < selectors.length; s++) {
- this.joinSelector(paths, context, selectors[s]);
- }
- },
-
- joinSelector: function (paths, context, selector) {
-
- var i, j, k,
- hasParentSelector, newSelectors, el, sel, parentSel,
- newSelectorPath, afterParentJoin, newJoinedSelector,
- newJoinedSelectorEmpty, lastSelector, currentElements,
- selectorsMultiplied;
-
- for (i = 0; i < selector.elements.length; i++) {
- el = selector.elements[i];
- if (el.value === '&') {
- hasParentSelector = true;
- }
- }
-
- if (!hasParentSelector) {
- if (context.length > 0) {
- for (i = 0; i < context.length; i++) {
- paths.push(context[i].concat(selector));
- }
- }
- else {
- paths.push([selector]);
- }
- return;
- }
-
- // The paths are [[Selector]]
- // The first list is a list of comma seperated selectors
- // The inner list is a list of inheritance seperated selectors
- // e.g.
- // .a, .b {
- // .c {
- // }
- // }
- // == [[.a] [.c]] [[.b] [.c]]
- //
-
- // the elements from the current selector so far
- currentElements = [];
- // the current list of new selectors to add to the path.
- // We will build it up. We initiate it with one empty selector as we "multiply" the new selectors
- // by the parents
- newSelectors = [[]];
-
- for (i = 0; i < selector.elements.length; i++) {
- el = selector.elements[i];
- // non parent reference elements just get added
- if (el.value !== "&") {
- currentElements.push(el);
- } else {
- // the new list of selectors to add
- selectorsMultiplied = [];
-
- // merge the current list of non parent selector elements
- // on to the current list of selectors to add
- if (currentElements.length > 0) {
- this.mergeElementsOnToSelectors(currentElements, newSelectors);
- }
-
- // loop through our current selectors
- for (j = 0; j < newSelectors.length; j++) {
- sel = newSelectors[j];
- // if we don't have any parent paths, the & might be in a mixin so that it can be used
- // whether there are parents or not
- if (context.length === 0) {
- // the combinator used on el should now be applied to the next element instead so that
- // it is not lost
- if (sel.length > 0) {
- sel[0].elements = sel[0].elements.slice(0);
- sel[0].elements.push(new(tree.Element)(el.combinator, '', 0, el.index, el.currentFileInfo));
- }
- selectorsMultiplied.push(sel);
- }
- else {
- // and the parent selectors
- for (k = 0; k < context.length; k++) {
- parentSel = context[k];
- // We need to put the current selectors
- // then join the last selector's elements on to the parents selectors
-
- // our new selector path
- newSelectorPath = [];
- // selectors from the parent after the join
- afterParentJoin = [];
- newJoinedSelectorEmpty = true;
-
- //construct the joined selector - if & is the first thing this will be empty,
- // if not newJoinedSelector will be the last set of elements in the selector
- if (sel.length > 0) {
- newSelectorPath = sel.slice(0);
- lastSelector = newSelectorPath.pop();
- newJoinedSelector = selector.createDerived(lastSelector.elements.slice(0));
- newJoinedSelectorEmpty = false;
- }
- else {
- newJoinedSelector = selector.createDerived([]);
- }
-
- //put together the parent selectors after the join
- if (parentSel.length > 1) {
- afterParentJoin = afterParentJoin.concat(parentSel.slice(1));
- }
-
- if (parentSel.length > 0) {
- newJoinedSelectorEmpty = false;
-
- // join the elements so far with the first part of the parent
- newJoinedSelector.elements.push(new(tree.Element)(el.combinator, parentSel[0].elements[0].value, el.index, el.currentFileInfo));
- newJoinedSelector.elements = newJoinedSelector.elements.concat(parentSel[0].elements.slice(1));
- }
-
- if (!newJoinedSelectorEmpty) {
- // now add the joined selector
- newSelectorPath.push(newJoinedSelector);
- }
-
- // and the rest of the parent
- newSelectorPath = newSelectorPath.concat(afterParentJoin);
-
- // add that to our new set of selectors
- selectorsMultiplied.push(newSelectorPath);
- }
- }
- }
-
- // our new selectors has been multiplied, so reset the state
- newSelectors = selectorsMultiplied;
- currentElements = [];
- }
- }
-
- // if we have any elements left over (e.g. .a& .b == .b)
- // add them on to all the current selectors
- if (currentElements.length > 0) {
- this.mergeElementsOnToSelectors(currentElements, newSelectors);
- }
-
- for (i = 0; i < newSelectors.length; i++) {
- if (newSelectors[i].length > 0) {
- paths.push(newSelectors[i]);
- }
- }
- },
-
- mergeElementsOnToSelectors: function(elements, selectors) {
- var i, sel;
-
- if (selectors.length === 0) {
- selectors.push([ new(tree.Selector)(elements) ]);
- return;
- }
-
- for (i = 0; i < selectors.length; i++) {
- sel = selectors[i];
-
- // if the previous thing in sel is a parent this needs to join on to it
- if (sel.length > 0) {
- sel[sel.length - 1] = sel[sel.length - 1].createDerived(sel[sel.length - 1].elements.concat(elements));
- }
- else {
- sel.push(new(tree.Selector)(elements));
- }
- }
- }
-};
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Selector = function (elements, extendList, condition, index, currentFileInfo, isReferenced) {
- this.elements = elements;
- this.extendList = extendList || [];
- this.condition = condition;
- this.currentFileInfo = currentFileInfo || {};
- this.isReferenced = isReferenced;
- if (!condition) {
- this.evaldCondition = true;
- }
-};
-tree.Selector.prototype = {
- type: "Selector",
- accept: function (visitor) {
- this.elements = visitor.visit(this.elements);
- this.extendList = visitor.visit(this.extendList);
- this.condition = visitor.visit(this.condition);
- },
- createDerived: function(elements, extendList, evaldCondition) {
- /*jshint eqnull:true */
- evaldCondition = evaldCondition != null ? evaldCondition : this.evaldCondition;
- var newSelector = new(tree.Selector)(elements, extendList || this.extendList, this.condition, this.index, this.currentFileInfo, this.isReferenced);
- newSelector.evaldCondition = evaldCondition;
- return newSelector;
- },
- match: function (other) {
- var elements = this.elements,
- len = elements.length,
- oelements, olen, max, i;
-
- oelements = other.elements.slice(
- (other.elements.length && other.elements[0].value === "&") ? 1 : 0);
- olen = oelements.length;
- max = Math.min(len, olen);
-
- if (olen === 0 || len < olen) {
- return 0;
- } else {
- for (i = 0; i < max; i++) {
- if (elements[i].value !== oelements[i].value) {
- return 0;
- }
- }
- }
- return max; // return number of matched selectors
- },
- eval: function (env) {
- var evaldCondition = this.condition && this.condition.eval(env);
-
- return this.createDerived(this.elements.map(function (e) {
- return e.eval(env);
- }), this.extendList.map(function(extend) {
- return extend.eval(env);
- }), evaldCondition);
- },
- genCSS: function (env, output) {
- var i, element;
- if ((!env || !env.firstSelector) && this.elements[0].combinator.value === "") {
- output.add(' ', this.currentFileInfo, this.index);
- }
- if (!this._css) {
- //TODO caching? speed comparison?
- for(i = 0; i < this.elements.length; i++) {
- element = this.elements[i];
- element.genCSS(env, output);
- }
- }
- },
- toCSS: tree.toCSS,
- markReferenced: function () {
- this.isReferenced = true;
- },
- getIsReferenced: function() {
- return !this.currentFileInfo.reference || this.isReferenced;
- },
- getIsOutput: function() {
- return this.evaldCondition;
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.UnicodeDescriptor = function (value) {
- this.value = value;
-};
-tree.UnicodeDescriptor.prototype = {
- type: "UnicodeDescriptor",
- genCSS: function (env, output) {
- output.add(this.value);
- },
- toCSS: tree.toCSS,
- eval: function () { return this; }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.URL = function (val, currentFileInfo) {
- this.value = val;
- this.currentFileInfo = currentFileInfo;
-};
-tree.URL.prototype = {
- type: "Url",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- genCSS: function (env, output) {
- output.add("url(");
- this.value.genCSS(env, output);
- output.add(")");
- },
- toCSS: tree.toCSS,
- eval: function (ctx) {
- var val = this.value.eval(ctx), rootpath;
-
- // Add the base path if the URL is relative
- rootpath = this.currentFileInfo && this.currentFileInfo.rootpath;
- if (rootpath && typeof val.value === "string" && ctx.isPathRelative(val.value)) {
- if (!val.quote) {
- rootpath = rootpath.replace(/[\(\)'"\s]/g, function(match) { return "\\"+match; });
- }
- val.value = rootpath + val.value;
- }
-
- val.value = ctx.normalizePath(val.value);
-
- return new(tree.URL)(val, null);
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Value = function (value) {
- this.value = value;
-};
-tree.Value.prototype = {
- type: "Value",
- accept: function (visitor) {
- this.value = visitor.visit(this.value);
- },
- eval: function (env) {
- if (this.value.length === 1) {
- return this.value[0].eval(env);
- } else {
- return new(tree.Value)(this.value.map(function (v) {
- return v.eval(env);
- }));
- }
- },
- genCSS: function (env, output) {
- var i;
- for(i = 0; i < this.value.length; i++) {
- this.value[i].genCSS(env, output);
- if (i+1 < this.value.length) {
- output.add((env && env.compress) ? ',' : ', ');
- }
- }
- },
- toCSS: tree.toCSS
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
-tree.Variable = function (name, index, currentFileInfo) {
- this.name = name;
- this.index = index;
- this.currentFileInfo = currentFileInfo;
-};
-tree.Variable.prototype = {
- type: "Variable",
- eval: function (env) {
- var variable, v, name = this.name;
-
- if (name.indexOf('@@') === 0) {
- name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
- }
-
- if (this.evaluating) {
- throw { type: 'Name',
- message: "Recursive variable definition for " + name,
- filename: this.currentFileInfo.file,
- index: this.index };
- }
-
- this.evaluating = true;
-
- if (variable = tree.find(env.frames, function (frame) {
- if (v = frame.variable(name)) {
- return v.value.eval(env);
- }
- })) {
- this.evaluating = false;
- return variable;
- }
- else {
- throw { type: 'Name',
- message: "variable " + name + " is undefined",
- filename: this.currentFileInfo.filename,
- index: this.index };
- }
- }
-};
-
-})(require('../tree'));
-
-(function (tree) {
-
- var parseCopyProperties = [
- 'paths', // option - unmodified - paths to search for imports on
- 'optimization', // option - optimization level (for the chunker)
- 'files', // list of files that have been imported, used for import-once
- 'contents', // browser-only, contents of all the files
- 'relativeUrls', // option - whether to adjust URL's to be relative
- 'rootpath', // option - rootpath to append to URL's
- 'strictImports', // option -
- 'insecure', // option - whether to allow imports from insecure ssl hosts
- 'dumpLineNumbers', // option - whether to dump line numbers
- 'compress', // option - whether to compress
- 'processImports', // option - whether to process imports. if false then imports will not be imported
- 'syncImport', // option - whether to import synchronously
- 'javascriptEnabled',// option - whether JavaScript is enabled. if undefined, defaults to true
- 'mime', // browser only - mime type for sheet import
- 'useFileCache', // browser only - whether to use the per file session cache
- 'currentFileInfo' // information about the current file - for error reporting and importing and making urls relative etc.
- ];
-
- //currentFileInfo = {
- // 'relativeUrls' - option - whether to adjust URL's to be relative
- // 'filename' - full resolved filename of current file
- // 'rootpath' - path to append to normal URLs for this node
- // 'currentDirectory' - path to the current file, absolute
- // 'rootFilename' - filename of the base file
- // 'entryPath' - absolute path to the entry file
- // 'reference' - whether the file should not be output and only output parts that are referenced
-
- tree.parseEnv = function(options) {
- copyFromOriginal(options, this, parseCopyProperties);
-
- if (!this.contents) { this.contents = {}; }
- if (!this.files) { this.files = {}; }
-
- if (!this.currentFileInfo) {
- var filename = (options && options.filename) || "input";
- var entryPath = filename.replace(/[^\/\\]*$/, "");
- if (options) {
- options.filename = null;
- }
- this.currentFileInfo = {
- filename: filename,
- relativeUrls: this.relativeUrls,
- rootpath: (options && options.rootpath) || "",
- currentDirectory: entryPath,
- entryPath: entryPath,
- rootFilename: filename
- };
- }
- };
-
- var evalCopyProperties = [
- 'silent', // whether to swallow errors and warnings
- 'verbose', // whether to log more activity
- 'compress', // whether to compress
- 'yuicompress', // whether to compress with the outside tool yui compressor
- 'ieCompat', // whether to enforce IE compatibility (IE8 data-uri)
- 'strictMath', // whether math has to be within parenthesis
- 'strictUnits', // whether units need to evaluate correctly
- 'cleancss', // whether to compress with clean-css
- 'sourceMap', // whether to output a source map
- 'importMultiple'// whether we are currently importing multiple copies
- ];
-
- tree.evalEnv = function(options, frames) {
- copyFromOriginal(options, this, evalCopyProperties);
-
- this.frames = frames || [];
- };
-
- tree.evalEnv.prototype.inParenthesis = function () {
- if (!this.parensStack) {
- this.parensStack = [];
- }
- this.parensStack.push(true);
- };
-
- tree.evalEnv.prototype.outOfParenthesis = function () {
- this.parensStack.pop();
- };
-
- tree.evalEnv.prototype.isMathOn = function () {
- return this.strictMath ? (this.parensStack && this.parensStack.length) : true;
- };
-
- tree.evalEnv.prototype.isPathRelative = function (path) {
- return !/^(?:[a-z-]+:|\/)/.test(path);
- };
-
- tree.evalEnv.prototype.normalizePath = function( path ) {
- var
- segments = path.split("/").reverse(),
- segment;
-
- path = [];
- while (segments.length !== 0 ) {
- segment = segments.pop();
- switch( segment ) {
- case ".":
- break;
- case "..":
- if ((path.length === 0) || (path[path.length - 1] === "..")) {
- path.push( segment );
- } else {
- path.pop();
- }
- break;
- default:
- path.push( segment );
- break;
- }
- }
-
- return path.join("/");
- };
-
- //todo - do the same for the toCSS env
- //tree.toCSSEnv = function (options) {
- //};
-
- var copyFromOriginal = function(original, destination, propertiesToCopy) {
- if (!original) { return; }
-
- for(var i = 0; i < propertiesToCopy.length; i++) {
- if (original.hasOwnProperty(propertiesToCopy[i])) {
- destination[propertiesToCopy[i]] = original[propertiesToCopy[i]];
- }
- }
- };
-
-})(require('./tree'));
-
-(function (tree) {
-
- tree.visitor = function(implementation) {
- this._implementation = implementation;
- };
-
- tree.visitor.prototype = {
- visit: function(node) {
-
- if (node instanceof Array) {
- return this.visitArray(node);
- }
-
- if (!node || !node.type) {
- return node;
- }
-
- var funcName = "visit" + node.type,
- func = this._implementation[funcName],
- visitArgs, newNode;
- if (func) {
- visitArgs = {visitDeeper: true};
- newNode = func.call(this._implementation, node, visitArgs);
- if (this._implementation.isReplacing) {
- node = newNode;
- }
- }
- if ((!visitArgs || visitArgs.visitDeeper) && node && node.accept) {
- node.accept(this);
- }
- funcName = funcName + "Out";
- if (this._implementation[funcName]) {
- this._implementation[funcName](node);
- }
- return node;
- },
- visitArray: function(nodes) {
- var i, newNodes = [];
- for(i = 0; i < nodes.length; i++) {
- var evald = this.visit(nodes[i]);
- if (evald instanceof Array) {
- evald = this.flatten(evald);
- newNodes = newNodes.concat(evald);
- } else {
- newNodes.push(evald);
- }
- }
- if (this._implementation.isReplacing) {
- return newNodes;
- }
- return nodes;
- },
- doAccept: function (node) {
- node.accept(this);
- },
- flatten: function(arr, master) {
- return arr.reduce(this.flattenReduce.bind(this), master || []);
- },
- flattenReduce: function(sum, element) {
- if (element instanceof Array) {
- sum = this.flatten(element, sum);
- } else {
- sum.push(element);
- }
- return sum;
- }
- };
-
-})(require('./tree'));
-(function (tree) {
- tree.importVisitor = function(importer, finish, evalEnv) {
- this._visitor = new tree.visitor(this);
- this._importer = importer;
- this._finish = finish;
- this.env = evalEnv || new tree.evalEnv();
- this.importCount = 0;
- };
-
- tree.importVisitor.prototype = {
- isReplacing: true,
- run: function (root) {
- var error;
- try {
- // process the contents
- this._visitor.visit(root);
- }
- catch(e) {
- error = e;
- }
-
- this.isFinished = true;
-
- if (this.importCount === 0) {
- this._finish(error);
- }
- },
- visitImport: function (importNode, visitArgs) {
- var importVisitor = this,
- evaldImportNode,
- inlineCSS = importNode.options.inline;
-
- if (!importNode.css || inlineCSS) {
-
- try {
- evaldImportNode = importNode.evalForImport(this.env);
- } catch(e){
- if (!e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
- // attempt to eval properly and treat as css
- importNode.css = true;
- // if that fails, this error will be thrown
- importNode.error = e;
- }
-
- if (evaldImportNode && (!evaldImportNode.css || inlineCSS)) {
- importNode = evaldImportNode;
- this.importCount++;
- var env = new tree.evalEnv(this.env, this.env.frames.slice(0));
-
- if (importNode.options.multiple) {
- env.importMultiple = true;
- }
-
- this._importer.push(importNode.getPath(), importNode.currentFileInfo, importNode.options, function (e, root, imported, fullPath) {
- if (e && !e.filename) { e.index = importNode.index; e.filename = importNode.currentFileInfo.filename; }
-
- if (imported && !env.importMultiple) { importNode.skip = imported; }
-
- var subFinish = function(e) {
- importVisitor.importCount--;
-
- if (importVisitor.importCount === 0 && importVisitor.isFinished) {
- importVisitor._finish(e);
- }
- };
-
- if (root) {
- importNode.root = root;
- importNode.importedFilename = fullPath;
- if (!inlineCSS && !importNode.skip) {
- new(tree.importVisitor)(importVisitor._importer, subFinish, env)
- .run(root);
- return;
- }
- }
-
- subFinish();
- });
- }
- }
- visitArgs.visitDeeper = false;
- return importNode;
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- return ruleNode;
- },
- visitDirective: function (directiveNode, visitArgs) {
- this.env.frames.unshift(directiveNode);
- return directiveNode;
- },
- visitDirectiveOut: function (directiveNode) {
- this.env.frames.shift();
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- this.env.frames.unshift(mixinDefinitionNode);
- return mixinDefinitionNode;
- },
- visitMixinDefinitionOut: function (mixinDefinitionNode) {
- this.env.frames.shift();
- },
- visitRuleset: function (rulesetNode, visitArgs) {
- this.env.frames.unshift(rulesetNode);
- return rulesetNode;
- },
- visitRulesetOut: function (rulesetNode) {
- this.env.frames.shift();
- },
- visitMedia: function (mediaNode, visitArgs) {
- this.env.frames.unshift(mediaNode.ruleset);
- return mediaNode;
- },
- visitMediaOut: function (mediaNode) {
- this.env.frames.shift();
- }
- };
-
-})(require('./tree'));
-(function (tree) {
- tree.joinSelectorVisitor = function() {
- this.contexts = [[]];
- this._visitor = new tree.visitor(this);
- };
-
- tree.joinSelectorVisitor.prototype = {
- run: function (root) {
- return this._visitor.visit(root);
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
-
- visitRuleset: function (rulesetNode, visitArgs) {
- var context = this.contexts[this.contexts.length - 1];
- var paths = [];
- this.contexts.push(paths);
-
- if (! rulesetNode.root) {
- rulesetNode.selectors = rulesetNode.selectors.filter(function(selector) { return selector.getIsOutput(); });
- if (rulesetNode.selectors.length === 0) {
- rulesetNode.rules.length = 0;
- }
- rulesetNode.joinSelectors(paths, context, rulesetNode.selectors);
- rulesetNode.paths = paths;
- }
- },
- visitRulesetOut: function (rulesetNode) {
- this.contexts.length = this.contexts.length - 1;
- },
- visitMedia: function (mediaNode, visitArgs) {
- var context = this.contexts[this.contexts.length - 1];
- mediaNode.rules[0].root = (context.length === 0 || context[0].multiMedia);
- }
- };
-
-})(require('./tree'));
-(function (tree) {
- tree.toCSSVisitor = function(env) {
- this._visitor = new tree.visitor(this);
- this._env = env;
- };
-
- tree.toCSSVisitor.prototype = {
- isReplacing: true,
- run: function (root) {
- return this._visitor.visit(root);
- },
-
- visitRule: function (ruleNode, visitArgs) {
- if (ruleNode.variable) {
- return [];
- }
- return ruleNode;
- },
-
- visitMixinDefinition: function (mixinNode, visitArgs) {
- return [];
- },
-
- visitExtend: function (extendNode, visitArgs) {
- return [];
- },
-
- visitComment: function (commentNode, visitArgs) {
- if (commentNode.isSilent(this._env)) {
- return [];
- }
- return commentNode;
- },
-
- visitMedia: function(mediaNode, visitArgs) {
- mediaNode.accept(this._visitor);
- visitArgs.visitDeeper = false;
-
- if (!mediaNode.rules.length) {
- return [];
- }
- return mediaNode;
- },
-
- visitDirective: function(directiveNode, visitArgs) {
- if (directiveNode.currentFileInfo.reference && !directiveNode.isReferenced) {
- return [];
- }
- if (directiveNode.name === "@charset") {
- // Only output the debug info together with subsequent @charset definitions
- // a comment (or @media statement) before the actual @charset directive would
- // be considered illegal css as it has to be on the first line
- if (this.charset) {
- if (directiveNode.debugInfo) {
- var comment = new tree.Comment("/* " + directiveNode.toCSS(this._env).replace(/\n/g, "")+" */\n");
- comment.debugInfo = directiveNode.debugInfo;
- return this._visitor.visit(comment);
- }
- return [];
- }
- this.charset = true;
- }
- return directiveNode;
- },
-
- checkPropertiesInRoot: function(rules) {
- var ruleNode;
- for(var i = 0; i < rules.length; i++) {
- ruleNode = rules[i];
- if (ruleNode instanceof tree.Rule && !ruleNode.variable) {
- throw { message: "properties must be inside selector blocks, they cannot be in the root.",
- index: ruleNode.index, filename: ruleNode.currentFileInfo ? ruleNode.currentFileInfo.filename : null};
- }
- }
- },
-
- visitRuleset: function (rulesetNode, visitArgs) {
- var rule, rulesets = [];
- if (rulesetNode.firstRoot) {
- this.checkPropertiesInRoot(rulesetNode.rules);
- }
- if (! rulesetNode.root) {
-
- rulesetNode.paths = rulesetNode.paths
- .filter(function(p) {
- var i;
- if (p[0].elements[0].combinator.value === ' ') {
- p[0].elements[0].combinator = new(tree.Combinator)('');
- }
- for(i = 0; i < p.length; i++) {
- if (p[i].getIsReferenced() && p[i].getIsOutput()) {
- return true;
- }
- return false;
- }
- });
-
- // Compile rules and rulesets
- for (var i = 0; i < rulesetNode.rules.length; i++) {
- rule = rulesetNode.rules[i];
-
- if (rule.rules) {
- // visit because we are moving them out from being a child
- rulesets.push(this._visitor.visit(rule));
- rulesetNode.rules.splice(i, 1);
- i--;
- continue;
- }
- }
- // accept the visitor to remove rules and refactor itself
- // then we can decide now whether we want it or not
- if (rulesetNode.rules.length > 0) {
- rulesetNode.accept(this._visitor);
- }
- visitArgs.visitDeeper = false;
-
- this._mergeRules(rulesetNode.rules);
- this._removeDuplicateRules(rulesetNode.rules);
-
- // now decide whether we keep the ruleset
- if (rulesetNode.rules.length > 0 && rulesetNode.paths.length > 0) {
- rulesets.splice(0, 0, rulesetNode);
- }
- } else {
- rulesetNode.accept(this._visitor);
- visitArgs.visitDeeper = false;
- if (rulesetNode.firstRoot || rulesetNode.rules.length > 0) {
- rulesets.splice(0, 0, rulesetNode);
- }
- }
- if (rulesets.length === 1) {
- return rulesets[0];
- }
- return rulesets;
- },
-
- _removeDuplicateRules: function(rules) {
- // remove duplicates
- var ruleCache = {},
- ruleList, rule, i;
- for(i = rules.length - 1; i >= 0 ; i--) {
- rule = rules[i];
- if (rule instanceof tree.Rule) {
- if (!ruleCache[rule.name]) {
- ruleCache[rule.name] = rule;
- } else {
- ruleList = ruleCache[rule.name];
- if (ruleList instanceof tree.Rule) {
- ruleList = ruleCache[rule.name] = [ruleCache[rule.name].toCSS(this._env)];
- }
- var ruleCSS = rule.toCSS(this._env);
- if (ruleList.indexOf(ruleCSS) !== -1) {
- rules.splice(i, 1);
- } else {
- ruleList.push(ruleCSS);
- }
- }
- }
- }
- },
-
- _mergeRules: function (rules) {
- var groups = {},
- parts,
- rule,
- key;
-
- for (var i = 0; i < rules.length; i++) {
- rule = rules[i];
-
- if ((rule instanceof tree.Rule) && rule.merge) {
- key = [rule.name,
- rule.important ? "!" : ""].join(",");
-
- if (!groups[key]) {
- parts = groups[key] = [];
- } else {
- rules.splice(i--, 1);
- }
-
- parts.push(rule);
- }
- }
-
- Object.keys(groups).map(function (k) {
- parts = groups[k];
-
- if (parts.length > 1) {
- rule = parts[0];
-
- rule.value = new (tree.Value)(parts.map(function (p) {
- return p.value;
- }));
- }
- });
- }
- };
-
-})(require('./tree'));
-(function (tree) {
- /*jshint loopfunc:true */
-
- tree.extendFinderVisitor = function() {
- this._visitor = new tree.visitor(this);
- this.contexts = [];
- this.allExtendsStack = [[]];
- };
-
- tree.extendFinderVisitor.prototype = {
- run: function (root) {
- root = this._visitor.visit(root);
- root.allExtends = this.allExtendsStack[0];
- return root;
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitRuleset: function (rulesetNode, visitArgs) {
-
- if (rulesetNode.root) {
- return;
- }
-
- var i, j, extend, allSelectorsExtendList = [], extendList;
-
- // get &:extend(.a); rules which apply to all selectors in this ruleset
- for(i = 0; i < rulesetNode.rules.length; i++) {
- if (rulesetNode.rules[i] instanceof tree.Extend) {
- allSelectorsExtendList.push(rulesetNode.rules[i]);
- rulesetNode.extendOnEveryPath = true;
- }
- }
-
- // now find every selector and apply the extends that apply to all extends
- // and the ones which apply to an individual extend
- for(i = 0; i < rulesetNode.paths.length; i++) {
- var selectorPath = rulesetNode.paths[i],
- selector = selectorPath[selectorPath.length-1];
- extendList = selector.extendList.slice(0).concat(allSelectorsExtendList).map(function(allSelectorsExtend) {
- return allSelectorsExtend.clone();
- });
- for(j = 0; j < extendList.length; j++) {
- this.foundExtends = true;
- extend = extendList[j];
- extend.findSelfSelectors(selectorPath);
- extend.ruleset = rulesetNode;
- if (j === 0) { extend.firstExtendOnThisSelectorPath = true; }
- this.allExtendsStack[this.allExtendsStack.length-1].push(extend);
- }
- }
-
- this.contexts.push(rulesetNode.selectors);
- },
- visitRulesetOut: function (rulesetNode) {
- if (!rulesetNode.root) {
- this.contexts.length = this.contexts.length - 1;
- }
- },
- visitMedia: function (mediaNode, visitArgs) {
- mediaNode.allExtends = [];
- this.allExtendsStack.push(mediaNode.allExtends);
- },
- visitMediaOut: function (mediaNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
- },
- visitDirective: function (directiveNode, visitArgs) {
- directiveNode.allExtends = [];
- this.allExtendsStack.push(directiveNode.allExtends);
- },
- visitDirectiveOut: function (directiveNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
- }
- };
-
- tree.processExtendsVisitor = function() {
- this._visitor = new tree.visitor(this);
- };
-
- tree.processExtendsVisitor.prototype = {
- run: function(root) {
- var extendFinder = new tree.extendFinderVisitor();
- extendFinder.run(root);
- if (!extendFinder.foundExtends) { return root; }
- root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
- this.allExtendsStack = [root.allExtends];
- return this._visitor.visit(root);
- },
- doExtendChaining: function (extendsList, extendsListTarget, iterationCount) {
- //
- // chaining is different from normal extension.. if we extend an extend then we are not just copying, altering and pasting
- // the selector we would do normally, but we are also adding an extend with the same target selector
- // this means this new extend can then go and alter other extends
- //
- // this method deals with all the chaining work - without it, extend is flat and doesn't work on other extend selectors
- // this is also the most expensive.. and a match on one selector can cause an extension of a selector we had already processed if
- // we look at each selector at a time, as is done in visitRuleset
-
- var extendIndex, targetExtendIndex, matches, extendsToAdd = [], newSelector, extendVisitor = this, selectorPath, extend, targetExtend, newExtend;
-
- iterationCount = iterationCount || 0;
-
- //loop through comparing every extend with every target extend.
- // a target extend is the one on the ruleset we are looking at copy/edit/pasting in place
- // e.g. .a:extend(.b) {} and .b:extend(.c) {} then the first extend extends the second one
- // and the second is the target.
- // the seperation into two lists allows us to process a subset of chains with a bigger set, as is the
- // case when processing media queries
- for(extendIndex = 0; extendIndex < extendsList.length; extendIndex++){
- for(targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++){
-
- extend = extendsList[extendIndex];
- targetExtend = extendsListTarget[targetExtendIndex];
-
- // look for circular references
- if (this.inInheritanceChain(targetExtend, extend)) { continue; }
-
- // find a match in the target extends self selector (the bit before :extend)
- selectorPath = [targetExtend.selfSelectors[0]];
- matches = extendVisitor.findMatch(extend, selectorPath);
-
- if (matches.length) {
-
- // we found a match, so for each self selector..
- extend.selfSelectors.forEach(function(selfSelector) {
-
- // process the extend as usual
- newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector);
-
- // but now we create a new extend from it
- newExtend = new(tree.Extend)(targetExtend.selector, targetExtend.option, 0);
- newExtend.selfSelectors = newSelector;
-
- // add the extend onto the list of extends for that selector
- newSelector[newSelector.length-1].extendList = [newExtend];
-
- // record that we need to add it.
- extendsToAdd.push(newExtend);
- newExtend.ruleset = targetExtend.ruleset;
-
- //remember its parents for circular references
- newExtend.parents = [targetExtend, extend];
-
- // only process the selector once.. if we have :extend(.a,.b) then multiple
- // extends will look at the same selector path, so when extending
- // we know that any others will be duplicates in terms of what is added to the css
- if (targetExtend.firstExtendOnThisSelectorPath) {
- newExtend.firstExtendOnThisSelectorPath = true;
- targetExtend.ruleset.paths.push(newSelector);
- }
- });
- }
- }
- }
-
- if (extendsToAdd.length) {
- // try to detect circular references to stop a stack overflow.
- // may no longer be needed.
- this.extendChainCount++;
- if (iterationCount > 100) {
- var selectorOne = "{unable to calculate}";
- var selectorTwo = "{unable to calculate}";
- try
- {
- selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
- selectorTwo = extendsToAdd[0].selector.toCSS();
- }
- catch(e) {}
- throw {message: "extend circular reference detected. One of the circular extends is currently:"+selectorOne+":extend(" + selectorTwo+")"};
- }
-
- // now process the new extends on the existing rules so that we can handle a extending b extending c ectending d extending e...
- return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount+1));
- } else {
- return extendsToAdd;
- }
- },
- inInheritanceChain: function (possibleParent, possibleChild) {
- if (possibleParent === possibleChild) {
- return true;
- }
- if (possibleChild.parents) {
- if (this.inInheritanceChain(possibleParent, possibleChild.parents[0])) {
- return true;
- }
- if (this.inInheritanceChain(possibleParent, possibleChild.parents[1])) {
- return true;
- }
- }
- return false;
- },
- visitRule: function (ruleNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitMixinDefinition: function (mixinDefinitionNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitSelector: function (selectorNode, visitArgs) {
- visitArgs.visitDeeper = false;
- },
- visitRuleset: function (rulesetNode, visitArgs) {
- if (rulesetNode.root) {
- return;
- }
- var matches, pathIndex, extendIndex, allExtends = this.allExtendsStack[this.allExtendsStack.length-1], selectorsToAdd = [], extendVisitor = this, selectorPath;
-
- // look at each selector path in the ruleset, find any extend matches and then copy, find and replace
-
- for(extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
- for(pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
-
- selectorPath = rulesetNode.paths[pathIndex];
-
- // extending extends happens initially, before the main pass
- if (rulesetNode.extendOnEveryPath || selectorPath[selectorPath.length-1].extendList.length) { continue; }
-
- matches = this.findMatch(allExtends[extendIndex], selectorPath);
-
- if (matches.length) {
-
- allExtends[extendIndex].selfSelectors.forEach(function(selfSelector) {
- selectorsToAdd.push(extendVisitor.extendSelector(matches, selectorPath, selfSelector));
- });
- }
- }
- }
- rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
- },
- findMatch: function (extend, haystackSelectorPath) {
- //
- // look through the haystack selector path to try and find the needle - extend.selector
- // returns an array of selector matches that can then be replaced
- //
- var haystackSelectorIndex, hackstackSelector, hackstackElementIndex, haystackElement,
- targetCombinator, i,
- extendVisitor = this,
- needleElements = extend.selector.elements,
- potentialMatches = [], potentialMatch, matches = [];
-
- // loop through the haystack elements
- for(haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
- hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
-
- for(hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
-
- haystackElement = hackstackSelector.elements[hackstackElementIndex];
-
- // if we allow elements before our match we can add a potential match every time. otherwise only at the first element.
- if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
- potentialMatches.push({pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0, initialCombinator: haystackElement.combinator});
- }
-
- for(i = 0; i < potentialMatches.length; i++) {
- potentialMatch = potentialMatches[i];
-
- // selectors add " " onto the first element. When we use & it joins the selectors together, but if we don't
- // then each selector in haystackSelectorPath has a space before it added in the toCSS phase. so we need to work out
- // what the resulting combinator will be
- targetCombinator = haystackElement.combinator.value;
- if (targetCombinator === '' && hackstackElementIndex === 0) {
- targetCombinator = ' ';
- }
-
- // if we don't match, null our match to indicate failure
- if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
- (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
- potentialMatch = null;
- } else {
- potentialMatch.matched++;
- }
-
- // if we are still valid and have finished, test whether we have elements after and whether these are allowed
- if (potentialMatch) {
- potentialMatch.finished = potentialMatch.matched === needleElements.length;
- if (potentialMatch.finished &&
- (!extend.allowAfter && (hackstackElementIndex+1 < hackstackSelector.elements.length || haystackSelectorIndex+1 < haystackSelectorPath.length))) {
- potentialMatch = null;
- }
- }
- // if null we remove, if not, we are still valid, so either push as a valid match or continue
- if (potentialMatch) {
- if (potentialMatch.finished) {
- potentialMatch.length = needleElements.length;
- potentialMatch.endPathIndex = haystackSelectorIndex;
- potentialMatch.endPathElementIndex = hackstackElementIndex + 1; // index after end of match
- potentialMatches.length = 0; // we don't allow matches to overlap, so start matching again
- matches.push(potentialMatch);
- }
- } else {
- potentialMatches.splice(i, 1);
- i--;
- }
- }
- }
- }
- return matches;
- },
- isElementValuesEqual: function(elementValue1, elementValue2) {
- if (typeof elementValue1 === "string" || typeof elementValue2 === "string") {
- return elementValue1 === elementValue2;
- }
- if (elementValue1 instanceof tree.Attribute) {
- if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
- return false;
- }
- if (!elementValue1.value || !elementValue2.value) {
- if (elementValue1.value || elementValue2.value) {
- return false;
- }
- return true;
- }
- elementValue1 = elementValue1.value.value || elementValue1.value;
- elementValue2 = elementValue2.value.value || elementValue2.value;
- return elementValue1 === elementValue2;
- }
- elementValue1 = elementValue1.value;
- elementValue2 = elementValue2.value;
- if (elementValue1 instanceof tree.Selector) {
- if (!(elementValue2 instanceof tree.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
- return false;
- }
- for(var i = 0; i <elementValue1.elements.length; i++) {
- if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
- if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
- return false;
- }
- }
- if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
- return false;
- }
- }
- return true;
- }
- return false;
- },
- extendSelector:function (matches, selectorPath, replacementSelector) {
-
- //for a set of matches, replace each match with the replacement selector
-
- var currentSelectorPathIndex = 0,
- currentSelectorPathElementIndex = 0,
- path = [],
- matchIndex,
- selector,
- firstElement,
- match,
- newElements;
-
- for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
- match = matches[matchIndex];
- selector = selectorPath[match.pathIndex];
- firstElement = new tree.Element(
- match.initialCombinator,
- replacementSelector.elements[0].value,
- replacementSelector.elements[0].index,
- replacementSelector.elements[0].currentFileInfo
- );
-
- if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
- path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
- currentSelectorPathElementIndex = 0;
- currentSelectorPathIndex++;
- }
-
- newElements = selector.elements
- .slice(currentSelectorPathElementIndex, match.index)
- .concat([firstElement])
- .concat(replacementSelector.elements.slice(1));
-
- if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
- path[path.length - 1].elements =
- path[path.length - 1].elements.concat(newElements);
- } else {
- path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
-
- path.push(new tree.Selector(
- newElements
- ));
- }
- currentSelectorPathIndex = match.endPathIndex;
- currentSelectorPathElementIndex = match.endPathElementIndex;
- if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
- currentSelectorPathElementIndex = 0;
- currentSelectorPathIndex++;
- }
- }
-
- if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
- path[path.length - 1].elements = path[path.length - 1].elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
- currentSelectorPathIndex++;
- }
-
- path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
-
- return path;
- },
- visitRulesetOut: function (rulesetNode) {
- },
- visitMedia: function (mediaNode, visitArgs) {
- var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
- newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
- this.allExtendsStack.push(newAllExtends);
- },
- visitMediaOut: function (mediaNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
- },
- visitDirective: function (directiveNode, visitArgs) {
- var newAllExtends = directiveNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length-1]);
- newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, directiveNode.allExtends));
- this.allExtendsStack.push(newAllExtends);
- },
- visitDirectiveOut: function (directiveNode) {
- this.allExtendsStack.length = this.allExtendsStack.length - 1;
- }
- };
-
-})(require('./tree'));
-
-(function (tree) {
-
- tree.sourceMapOutput = function (options) {
- this._css = [];
- this._rootNode = options.rootNode;
- this._writeSourceMap = options.writeSourceMap;
- this._contentsMap = options.contentsMap;
- this._sourceMapFilename = options.sourceMapFilename;
- this._outputFilename = options.outputFilename;
- this._sourceMapBasepath = options.sourceMapBasepath;
- this._sourceMapRootpath = options.sourceMapRootpath;
- this._outputSourceFiles = options.outputSourceFiles;
- this._sourceMapGeneratorConstructor = options.sourceMapGenerator || require("source-map").SourceMapGenerator;
-
- if (this._sourceMapRootpath && this._sourceMapRootpath.charAt(this._sourceMapRootpath.length-1) !== '/') {
- this._sourceMapRootpath += '/';
- }
-
- this._lineNumber = 0;
- this._column = 0;
- };
-
- tree.sourceMapOutput.prototype.normalizeFilename = function(filename) {
- if (this._sourceMapBasepath && filename.indexOf(this._sourceMapBasepath) === 0) {
- filename = filename.substring(this._sourceMapBasepath.length);
- if (filename.charAt(0) === '\\' || filename.charAt(0) === '/') {
- filename = filename.substring(1);
- }
- }
- return (this._sourceMapRootpath || "") + filename.replace(/\\/g, '/');
- };
-
- tree.sourceMapOutput.prototype.add = function(chunk, fileInfo, index, mapLines) {
-
- //ignore adding empty strings
- if (!chunk) {
- return;
- }
-
- var lines,
- sourceLines,
- columns,
- sourceColumns,
- i;
-
- if (fileInfo) {
- var inputSource = this._contentsMap[fileInfo.filename].substring(0, index);
- sourceLines = inputSource.split("\n");
- sourceColumns = sourceLines[sourceLines.length-1];
- }
-
- lines = chunk.split("\n");
- columns = lines[lines.length-1];
-
- if (fileInfo) {
- if (!mapLines) {
- this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + 1, column: this._column},
- original: { line: sourceLines.length, column: sourceColumns.length},
- source: this.normalizeFilename(fileInfo.filename)});
- } else {
- for(i = 0; i < lines.length; i++) {
- this._sourceMapGenerator.addMapping({ generated: { line: this._lineNumber + i + 1, column: i === 0 ? this._column : 0},
- original: { line: sourceLines.length + i, column: i === 0 ? sourceColumns.length : 0},
- source: this.normalizeFilename(fileInfo.filename)});
- }
- }
- }
-
- if (lines.length === 1) {
- this._column += columns.length;
- } else {
- this._lineNumber += lines.length - 1;
- this._column = columns.length;
- }
-
- this._css.push(chunk);
- };
-
- tree.sourceMapOutput.prototype.isEmpty = function() {
- return this._css.length === 0;
- };
-
- tree.sourceMapOutput.prototype.toCSS = function(env) {
- this._sourceMapGenerator = new this._sourceMapGeneratorConstructor({ file: this._outputFilename, sourceRoot: null });
-
- if (this._outputSourceFiles) {
- for(var filename in this._contentsMap) {
- this._sourceMapGenerator.setSourceContent(this.normalizeFilename(filename), this._contentsMap[filename]);
- }
- }
-
- this._rootNode.genCSS(env, this);
-
- if (this._css.length > 0) {
- var sourceMapFilename,
- sourceMapContent = JSON.stringify(this._sourceMapGenerator.toJSON());
-
- if (this._sourceMapFilename) {
- sourceMapFilename = this.normalizeFilename(this._sourceMapFilename);
- }
-
- if (this._writeSourceMap) {
- this._writeSourceMap(sourceMapContent);
- } else {
- sourceMapFilename = "data:application/json," + encodeURIComponent(sourceMapContent);
- }
-
- if (sourceMapFilename) {
- this._css.push("/*# sourceMappingURL=" + sourceMapFilename + " */");
- }
- }
-
- return this._css.join('');
- };
-
-})(require('./tree'));
-
-//
-// browser.js - client-side engine
-//
-/*global less, window, document, XMLHttpRequest, location */
-
-var isFileProtocol = /^(file|chrome(-extension)?|resource|qrc|app):/.test(location.protocol);
-
-less.env = less.env || (location.hostname == '127.0.0.1' ||
- location.hostname == '0.0.0.0' ||
- location.hostname == 'localhost' ||
- (location.port &&
- location.port.length > 0) ||
- isFileProtocol ? 'development'
- : 'production');
-
-var logLevel = {
- info: 2,
- errors: 1,
- none: 0
-};
-
-// The amount of logging in the javascript console.
-// 2 - Information and errors
-// 1 - Errors
-// 0 - None
-// Defaults to 2
-less.logLevel = typeof(less.logLevel) != 'undefined' ? less.logLevel : logLevel.info;
-
-// Load styles asynchronously (default: false)
-//
-// This is set to `false` by default, so that the body
-// doesn't start loading before the stylesheets are parsed.
-// Setting this to `true` can result in flickering.
-//
-less.async = less.async || false;
-less.fileAsync = less.fileAsync || false;
-
-// Interval between watch polls
-less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
-
-//Setup user functions
-if (less.functions) {
- for(var func in less.functions) {
- less.tree.functions[func] = less.functions[func];
- }
-}
-
-var dumpLineNumbers = /!dumpLineNumbers:(comments|mediaquery|all)/.exec(location.hash);
-if (dumpLineNumbers) {
- less.dumpLineNumbers = dumpLineNumbers[1];
-}
-
-var typePattern = /^text\/(x-)?less$/;
-var cache = null;
-var fileCache = {};
-var varsPre = "";
-
-function log(str, level) {
- if (less.env == 'development' && typeof(console) !== 'undefined' && less.logLevel >= level) {
- console.log('less: ' + str);
- }
-}
-
-function extractId(href) {
- return href.replace(/^[a-z-]+:\/+?[^\/]+/, '' ) // Remove protocol & domain
- .replace(/^\//, '' ) // Remove root /
- .replace(/\.[a-zA-Z]+$/, '' ) // Remove simple extension
- .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
- .replace(/\./g, ':'); // Replace dots with colons(for valid id)
-}
-
-function errorConsole(e, rootHref) {
- var template = '{line} {content}';
- var filename = e.filename || rootHref;
- var errors = [];
- var content = (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
- " in " + filename + " ";
-
- var errorline = function (e, i, classname) {
- if (e.extract[i] !== undefined) {
- errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
- .replace(/\{class\}/, classname)
- .replace(/\{content\}/, e.extract[i]));
- }
- };
-
- if (e.extract) {
- errorline(e, 0, '');
- errorline(e, 1, 'line');
- errorline(e, 2, '');
- content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':\n' +
- errors.join('\n');
- } else if (e.stack) {
- content += e.stack;
- }
- log(content, logLevel.errors);
-}
-
-function createCSS(styles, sheet, lastModified) {
- // Strip the query-string
- var href = sheet.href || '';
-
- // If there is no title set, use the filename, minus the extension
- var id = 'less:' + (sheet.title || extractId(href));
-
- // If this has already been inserted into the DOM, we may need to replace it
- var oldCss = document.getElementById(id);
- var keepOldCss = false;
-
- // Create a new stylesheet node for insertion or (if necessary) replacement
- var css = document.createElement('style');
- css.setAttribute('type', 'text/css');
- if (sheet.media) {
- css.setAttribute('media', sheet.media);
- }
- css.id = id;
-
- if (css.styleSheet) { // IE
- try {
- css.styleSheet.cssText = styles;
- } catch (e) {
- throw new(Error)("Couldn't reassign styleSheet.cssText.");
- }
- } else {
- css.appendChild(document.createTextNode(styles));
-
- // If new contents match contents of oldCss, don't replace oldCss
- keepOldCss = (oldCss !== null && oldCss.childNodes.length > 0 && css.childNodes.length > 0 &&
- oldCss.firstChild.nodeValue === css.firstChild.nodeValue);
- }
-
- var head = document.getElementsByTagName('head')[0];
-
- // If there is no oldCss, just append; otherwise, only append if we need
- // to replace oldCss with an updated stylesheet
- if (oldCss === null || keepOldCss === false) {
- var nextEl = sheet && sheet.nextSibling || null;
- if (nextEl) {
- nextEl.parentNode.insertBefore(css, nextEl);
- } else {
- head.appendChild(css);
- }
- }
- if (oldCss && keepOldCss === false) {
- oldCss.parentNode.removeChild(oldCss);
- }
-
- // Don't update the local store if the file wasn't modified
- if (lastModified && cache) {
- log('saving ' + href + ' to cache.', logLevel.info);
- try {
- cache.setItem(href, styles);
- cache.setItem(href + ':timestamp', lastModified);
- } catch(e) {
- //TODO - could do with adding more robust error handling
- log('failed to save', logLevel.errors);
- }
- }
-}
-
-function errorHTML(e, rootHref) {
- var id = 'less-error-message:' + extractId(rootHref || "");
- var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
- var elem = document.createElement('div'), timer, content, errors = [];
- var filename = e.filename || rootHref;
- var filenameNoPath = filename.match(/([^\/]+(\?.*)?)$/)[1];
-
- elem.id = id;
- elem.className = "less-error-message";
-
- content = '<h3>' + (e.type || "Syntax") + "Error: " + (e.message || 'There is an error in your .less file') +
- '</h3>' + '<p>in <a href="' + filename + '">' + filenameNoPath + "</a> ";
-
- var errorline = function (e, i, classname) {
- if (e.extract[i] !== undefined) {
- errors.push(template.replace(/\{line\}/, (parseInt(e.line, 10) || 0) + (i - 1))
- .replace(/\{class\}/, classname)
- .replace(/\{content\}/, e.extract[i]));
- }
- };
-
- if (e.extract) {
- errorline(e, 0, '');
- errorline(e, 1, 'line');
- errorline(e, 2, '');
- content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
- '<ul>' + errors.join('') + '</ul>';
- } else if (e.stack) {
- content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
- }
- elem.innerHTML = content;
-
- // CSS for error messages
- createCSS([
- '.less-error-message ul, .less-error-message li {',
- 'list-style-type: none;',
- 'margin-right: 15px;',
- 'padding: 4px 0;',
- 'margin: 0;',
- '}',
- '.less-error-message label {',
- 'font-size: 12px;',
- 'margin-right: 15px;',
- 'padding: 4px 0;',
- 'color: #cc7777;',
- '}',
- '.less-error-message pre {',
- 'color: #dd6666;',
- 'padding: 4px 0;',
- 'margin: 0;',
- 'display: inline-block;',
- '}',
- '.less-error-message pre.line {',
- 'color: #ff0000;',
- '}',
- '.less-error-message h3 {',
- 'font-size: 20px;',
- 'font-weight: bold;',
- 'padding: 15px 0 5px 0;',
- 'margin: 0;',
- '}',
- '.less-error-message a {',
- 'color: #10a',
- '}',
- '.less-error-message .error {',
- 'color: red;',
- 'font-weight: bold;',
- 'padding-bottom: 2px;',
- 'border-bottom: 1px dashed red;',
- '}'
- ].join('\n'), { title: 'error-message' });
-
- elem.style.cssText = [
- "font-family: Arial, sans-serif",
- "border: 1px solid #e00",
- "background-color: #eee",
- "border-radius: 5px",
- "-webkit-border-radius: 5px",
- "-moz-border-radius: 5px",
- "color: #e00",
- "padding: 15px",
- "margin-bottom: 15px"
- ].join(';');
-
- if (less.env == 'development') {
- timer = setInterval(function () {
- if (document.body) {
- if (document.getElementById(id)) {
- document.body.replaceChild(elem, document.getElementById(id));
- } else {
- document.body.insertBefore(elem, document.body.firstChild);
- }
- clearInterval(timer);
- }
- }, 10);
- }
-}
-
-function error(e, rootHref) {
- if (!less.errorReporting || less.errorReporting === "html") {
- errorHTML(e, rootHref);
- } else if (less.errorReporting === "console") {
- errorConsole(e, rootHref);
- } else if (typeof less.errorReporting === 'function') {
- less.errorReporting("add", e, rootHref);
- }
-}
-
-function removeErrorHTML(path) {
- var node = document.getElementById('less-error-message:' + extractId(path));
- if (node) {
- node.parentNode.removeChild(node);
- }
-}
-
-function removeErrorConsole(path) {
- //no action
-}
-
-function removeError(path) {
- if (!less.errorReporting || less.errorReporting === "html") {
- removeErrorHTML(path);
- } else if (less.errorReporting === "console") {
- removeErrorConsole(path);
- } else if (typeof less.errorReporting === 'function') {
- less.errorReporting("remove", path);
- }
-}
-
-function loadStyles(newVars) {
- var styles = document.getElementsByTagName('style'),
- style;
- for (var i = 0; i < styles.length; i++) {
- style = styles[i];
- if (style.type.match(typePattern)) {
- var env = new less.tree.parseEnv(less),
- lessText = style.innerHTML || '';
- env.filename = document.location.href.replace(/#.*$/, '');
-
- if (newVars || varsPre) {
- env.useFileCache = true;
-
- lessText = varsPre + lessText;
-
- if (newVars) {
- lessText += "\n" + newVars;
- }
- }
-
- /*jshint loopfunc:true */
- // use closure to store current value of i
- var callback = (function(style) {
- return function (e, cssAST) {
- if (e) {
- return error(e, "inline");
- }
- var css = cssAST.toCSS(less);
- style.type = 'text/css';
- if (style.styleSheet) {
- style.styleSheet.cssText = css;
- } else {
- style.innerHTML = css;
- }
- };
- })(style);
- new(less.Parser)(env).parse(lessText, callback);
- }
- }
-}
-
-function extractUrlParts(url, baseUrl) {
- // urlParts[1] = protocol&hostname || /
- // urlParts[2] = / if path relative to host base
- // urlParts[3] = directories
- // urlParts[4] = filename
- // urlParts[5] = parameters
-
- var urlPartsRegex = /^((?:[a-z-]+:)?\/+?(?:[^\/\?#]*\/)|([\/\\]))?((?:[^\/\\\?#]*[\/\\])*)([^\/\\\?#]*)([#\?].*)?$/i,
- urlParts = url.match(urlPartsRegex),
- returner = {}, directories = [], i, baseUrlParts;
-
- if (!urlParts) {
- throw new Error("Could not parse sheet href - '"+url+"'");
- }
-
- // Stylesheets in IE don't always return the full path
- if (!urlParts[1] || urlParts[2]) {
- baseUrlParts = baseUrl.match(urlPartsRegex);
- if (!baseUrlParts) {
- throw new Error("Could not parse page url - '"+baseUrl+"'");
- }
- urlParts[1] = urlParts[1] || baseUrlParts[1] || "";
- if (!urlParts[2]) {
- urlParts[3] = baseUrlParts[3] + urlParts[3];
- }
- }
-
- if (urlParts[3]) {
- directories = urlParts[3].replace(/\\/g, "/").split("/");
-
- // extract out . before .. so .. doesn't absorb a non-directory
- for(i = 0; i < directories.length; i++) {
- if (directories[i] === ".") {
- directories.splice(i, 1);
- i -= 1;
- }
- }
-
- for(i = 0; i < directories.length; i++) {
- if (directories[i] === ".." && i > 0) {
- directories.splice(i-1, 2);
- i -= 2;
- }
- }
- }
-
- returner.hostPart = urlParts[1];
- returner.directories = directories;
- returner.path = urlParts[1] + directories.join("/");
- returner.fileUrl = returner.path + (urlParts[4] || "");
- returner.url = returner.fileUrl + (urlParts[5] || "");
- return returner;
-}
-
-function pathDiff(url, baseUrl) {
- // diff between two paths to create a relative path
-
- var urlParts = extractUrlParts(url),
- baseUrlParts = extractUrlParts(baseUrl),
- i, max, urlDirectories, baseUrlDirectories, diff = "";
- if (urlParts.hostPart !== baseUrlParts.hostPart) {
- return "";
- }
- max = Math.max(baseUrlParts.directories.length, urlParts.directories.length);
- for(i = 0; i < max; i++) {
- if (baseUrlParts.directories[i] !== urlParts.directories[i]) { break; }
- }
- baseUrlDirectories = baseUrlParts.directories.slice(i);
- urlDirectories = urlParts.directories.slice(i);
- for(i = 0; i < baseUrlDirectories.length-1; i++) {
- diff += "../";
- }
- for(i = 0; i < urlDirectories.length-1; i++) {
- diff += urlDirectories[i] + "/";
- }
- return diff;
-}
-
-function getXMLHttpRequest() {
- if (window.XMLHttpRequest) {
- return new XMLHttpRequest();
- } else {
- try {
- /*global ActiveXObject */
- return new ActiveXObject("MSXML2.XMLHTTP.3.0");
- } catch (e) {
- log("browser doesn't support AJAX.", logLevel.errors);
- return null;
- }
- }
-}
-
-function doXHR(url, type, callback, errback) {
- var xhr = getXMLHttpRequest();
- var async = isFileProtocol ? less.fileAsync : less.async;
-
- if (typeof(xhr.overrideMimeType) === 'function') {
- xhr.overrideMimeType('text/css');
- }
- log("XHR: Getting '" + url + "'", logLevel.info);
- xhr.open('GET', url, async);
- xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
- xhr.send(null);
-
- function handleResponse(xhr, callback, errback) {
- if (xhr.status >= 200 && xhr.status < 300) {
- callback(xhr.responseText,
- xhr.getResponseHeader("Last-Modified"));
- } else if (typeof(errback) === 'function') {
- errback(xhr.status, url);
- }
- }
-
- if (isFileProtocol && !less.fileAsync) {
- if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
- callback(xhr.responseText);
- } else {
- errback(xhr.status, url);
- }
- } else if (async) {
- xhr.onreadystatechange = function () {
- if (xhr.readyState == 4) {
- handleResponse(xhr, callback, errback);
- }
- };
- } else {
- handleResponse(xhr, callback, errback);
- }
-}
-
-function loadFile(originalHref, currentFileInfo, callback, env, newVars) {
-
- if (currentFileInfo && currentFileInfo.currentDirectory && !/^([a-z-]+:)?\//.test(originalHref)) {
- originalHref = currentFileInfo.currentDirectory + originalHref;
- }
-
- // sheet may be set to the stylesheet for the initial load or a collection of properties including
- // some env variables for imports
- var hrefParts = extractUrlParts(originalHref, window.location.href);
- var href = hrefParts.url;
- var newFileInfo = {
- currentDirectory: hrefParts.path,
- filename: href
- };
-
- if (currentFileInfo) {
- newFileInfo.entryPath = currentFileInfo.entryPath;
- newFileInfo.rootpath = currentFileInfo.rootpath;
- newFileInfo.rootFilename = currentFileInfo.rootFilename;
- newFileInfo.relativeUrls = currentFileInfo.relativeUrls;
- } else {
- newFileInfo.entryPath = hrefParts.path;
- newFileInfo.rootpath = less.rootpath || hrefParts.path;
- newFileInfo.rootFilename = href;
- newFileInfo.relativeUrls = env.relativeUrls;
- }
-
- if (newFileInfo.relativeUrls) {
- if (env.rootpath) {
- newFileInfo.rootpath = extractUrlParts(env.rootpath + pathDiff(hrefParts.path, newFileInfo.entryPath)).path;
- } else {
- newFileInfo.rootpath = hrefParts.path;
- }
- }
-
- if (env.useFileCache && fileCache[href]) {
- try {
- var lessText = fileCache[href];
- if (newVars) {
- lessText += "\n" + newVars;
- }
- callback(null, lessText, href, newFileInfo, { lastModified: new Date() });
- } catch (e) {
- callback(e, null, href);
- }
- return;
- }
-
- doXHR(href, env.mime, function (data, lastModified) {
- data = varsPre + data;
-
- // per file cache
- fileCache[href] = data;
-
- // Use remote copy (re-parse)
- try {
- callback(null, data, href, newFileInfo, { lastModified: lastModified });
- } catch (e) {
- callback(e, null, href);
- }
- }, function (status, url) {
- callback({ type: 'File', message: "'" + url + "' wasn't found (" + status + ")" }, null, href);
- });
-}
-
-function loadStyleSheet(sheet, callback, reload, remaining, newVars) {
-
- var env = new less.tree.parseEnv(less);
- env.mime = sheet.type;
-
- if (newVars || varsPre) {
- env.useFileCache = true;
- }
-
- loadFile(sheet.href, null, function(e, data, path, newFileInfo, webInfo) {
-
- if (webInfo) {
- webInfo.remaining = remaining;
-
- var css = cache && cache.getItem(path),
- timestamp = cache && cache.getItem(path + ':timestamp');
-
- if (!reload && timestamp && webInfo.lastModified &&
- (new(Date)(webInfo.lastModified).valueOf() ===
- new(Date)(timestamp).valueOf())) {
- // Use local copy
- createCSS(css, sheet);
- webInfo.local = true;
- callback(null, null, data, sheet, webInfo, path);
- return;
- }
- }
-
- //TODO add tests around how this behaves when reloading
- removeError(path);
-
- if (data) {
- env.currentFileInfo = newFileInfo;
- new(less.Parser)(env).parse(data, function (e, root) {
- if (e) { return callback(e, null, null, sheet); }
- try {
- callback(e, root, data, sheet, webInfo, path);
- } catch (e) {
- callback(e, null, null, sheet);
- }
- });
- } else {
- callback(e, null, null, sheet, webInfo, path);
- }
- }, env, newVars);
-}
-
-function loadStyleSheets(callback, reload, newVars) {
- for (var i = 0; i < less.sheets.length; i++) {
- loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1), newVars);
- }
-}
-
-function initRunningMode(){
- if (less.env === 'development') {
- less.optimization = 0;
- less.watchTimer = setInterval(function () {
- if (less.watchMode) {
- loadStyleSheets(function (e, root, _, sheet, env) {
- if (e) {
- error(e, sheet.href);
- } else if (root) {
- createCSS(root.toCSS(less), sheet, env.lastModified);
- }
- });
- }
- }, less.poll);
- } else {
- less.optimization = 3;
- }
-}
-
-function serializeVars(vars) {
- var s = "";
-
- for (var name in vars) {
- s += ((name.slice(0,1) === '@')? '' : '@') + name +': '+
- ((vars[name].slice(-1) === ';')? vars[name] : vars[name] +';');
- }
-
- return s;
-}
-
-
-//
-// Watch mode
-//
-less.watch = function () {
- if (!less.watchMode ){
- less.env = 'development';
- initRunningMode();
- }
- return this.watchMode = true;
-};
-
-less.unwatch = function () {clearInterval(less.watchTimer); return this.watchMode = false; };
-
-if (/!watch/.test(location.hash)) {
- less.watch();
-}
-
-if (less.env != 'development') {
- try {
- cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
- } catch (_) {}
-}
-
-//
-// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
-//
-var links = document.getElementsByTagName('link');
-
-less.sheets = [];
-
-for (var i = 0; i < links.length; i++) {
- if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
- (links[i].type.match(typePattern)))) {
- less.sheets.push(links[i]);
- }
-}
-
-//
-// With this function, it's possible to alter variables and re-render
-// CSS without reloading less-files
-//
-less.modifyVars = function(record) {
- less.refresh(false, serializeVars(record));
-};
-
-less.refresh = function (reload, newVars) {
- var startTime, endTime;
- startTime = endTime = new Date();
-
- loadStyleSheets(function (e, root, _, sheet, env) {
- if (e) {
- return error(e, sheet.href);
- }
- if (env.local) {
- log("loading " + sheet.href + " from cache.", logLevel.info);
- } else {
- log("parsed " + sheet.href + " successfully.", logLevel.info);
- createCSS(root.toCSS(less), sheet, env.lastModified);
- }
- log("css for " + sheet.href + " generated in " + (new Date() - endTime) + 'ms', logLevel.info);
- if (env.remaining === 0) {
- log("css generated in " + (new Date() - startTime) + 'ms', logLevel.info);
- }
- endTime = new Date();
- }, reload, newVars);
-
- loadStyles(newVars);
-};
-
-if (less.globalVars) {
- varsPre = serializeVars(less.globalVars) + "\n";
-}
-
-less.refreshStyles = loadStyles;
-
-less.Parser.fileLoader = loadFile;
-
-less.refresh(less.env === 'development');
-
-// amd.js
-//
-// Define Less as an AMD module.
-if (typeof define === "function" && define.amd) {
- define(function () { return less; } );
-}
-
-})(window);
\ No newline at end of file
+++ /dev/null
-.a {
- prop: (3 / #fff);
-}
\ No newline at end of file
+++ /dev/null
-less: OperationError: Can't substract or divide a color from a number in {pathhref}console-errors/test-error.less on line null, column 0:
-1 prop: (3 / #fff);
+++ /dev/null
-.test {
- color: @global-var;
-}
+++ /dev/null
-@import "modify-this.css";
-.modify {
- my-url: url("a.png");
-}
\ No newline at end of file
+++ /dev/null
-@import "modify-again.css";
-.modify {
- my-url: url("b.png");
-}
\ No newline at end of file
+++ /dev/null
-@var2: blue;
-.testisimported {
- color: gainsboro;
-}
\ No newline at end of file
+++ /dev/null
-@import "imports/simple2";
-@var1: red;
-.test {
- color1: @var1;
- color2: @var2;
-}
\ No newline at end of file
+++ /dev/null
-@import ".././imports/urls.less";
-@import "http://localhost:8081/test/browser/less/imports/urls2.less";
-@font-face {
- src: local(Futura-Medium),
- url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- @a: 'Trebuchet';
- url: url(@a);
-}
+++ /dev/null
-@import "../imports/urls.less";
-@import "http://localhost:8081/test/browser/less/imports/urls2.less";
-@font-face {
- src: local(Futura-Medium),
- url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- @a: 'Trebuchet';
- url: url(@a);
-}
+++ /dev/null
-@import "../imports/urls.less";
-@import "http://localhost:8081/test/browser/less/imports/urls2.less";
-@font-face {
- src: local(Futura-Medium),
- url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- @a: 'Trebuchet';
- url: url(@a);
-}
+++ /dev/null
-@import "imports/urls.less";
-@import "http://localhost:8081/test/browser/less/imports/urls2.less";
-@font-face {
- src: local(Futura-Medium),
- url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- @a: 'Trebuchet';
- url: url(@a);
-}
-#data-uri {
- uri: data-uri('image/jpeg;base64', '../../data/image.jpg');
-}
-
-#data-uri-guess {
- uri: data-uri('../../data/image.jpg');
-}
-
-#data-uri-ascii {
- uri-1: data-uri('text/html', '../../data/page.html');
- uri-2: data-uri('../../data/page.html');
-}
-
-#data-uri-toobig {
- uri: data-uri('../../data/data-uri-fail.png');
-}
-#svg-functions {
- background-image: svg-gradient(to bottom, black, white);
- background-image: svg-gradient(to bottom, black, orange 3%, white);
- @green_5: green 5%;
- @orange_percentage: 3%;
- @orange_color: orange;
- background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%);
-}
+++ /dev/null
-var webpage = require('webpage');
-var server = require('webserver').create();
-var system = require('system');
-var fs = require('fs');
-var host;
-var port = 8081;
-
-var listening = server.listen(port, function(request, response) {
- //console.log("Requested " + request.url);
-
- var filename = ("test/" + request.url.slice(1)).replace(/[\\\/]/g, fs.separator);
-
- if (!fs.exists(filename) || !fs.isFile(filename)) {
- response.statusCode = 404;
- response.write("<html><head></head><body><h1>File Not Found</h1><h2>File:" + filename + "</h2></body></html>");
- response.close();
- return;
- }
-
- // we set the headers here
- response.statusCode = 200;
- response.headers = {
- "Cache": "no-cache",
- "Content-Type": "text/html"
- };
-
- response.write(fs.read(filename));
-
- response.close();
-});
-if (!listening) {
- console.log("could not create web server listening on port " + port);
- phantom.exit();
-}
-
-/**
- * Wait until the test condition is true or a timeout occurs. Useful for waiting
- * on a server response or for a ui change (fadeIn, etc.) to occur.
- *
- * @param testFx javascript condition that evaluates to a boolean,
- * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
- * as a callback function.
- * @param onReady what to do when testFx condition is fulfilled,
- * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
- * as a callback function.
- * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
- * @param timeOutErrorMessage the error message if time out occurs
- */
-
-function waitFor(testFx, onReady, timeOutMillis, timeOutErrorMessage) {
- var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 10001, //< Default Max Timeout is 10s
- start = new Date().getTime(),
- condition = false,
- interval = setInterval(function() {
- if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
- // If not time-out yet and condition not yet fulfilled
- condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
- } else {
- if (!condition) {
- // If condition still not fulfilled (timeout but condition is 'false')
- console.log(timeOutErrorMessage || "'waitFor()' timeout");
- phantom.exit(1);
- } else {
- // Condition fulfilled (timeout and/or condition is 'true')
- typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
- clearInterval(interval); //< Stop this interval
- }
- }
- }, 100); //< repeat check every 100ms
-}
-
-function testPage(url) {
- var page = webpage.create();
- page.open(url, function(status) {
- if (status !== "success") {
- console.log("Unable to access network - " + status);
- phantom.exit();
- } else {
- waitFor(function() {
- return page.evaluate(function() {
- return document.body && document.body.querySelector &&
- document.body.querySelector('.symbolSummary .pending') === null &&
- document.body.querySelector('.results') !== null;
- });
- }, function() {
- page.onConsoleMessage = function(msg) {
- console.log(msg);
- };
- var exitCode = page.evaluate(function() {
- console.log('');
- console.log(document.body.querySelector('.description').innerText);
- var list = document.body.querySelectorAll('.results > #details > .specDetail.failed');
- if (list && list.length > 0) {
- console.log('');
- console.log(list.length + ' test(s) FAILED:');
- for (var i = 0; i < list.length; ++i) {
- var el = list[i],
- desc = el.querySelector('.description'),
- msg = el.querySelector('.resultMessage.fail');
- console.log('');
- console.log(desc.innerText);
- console.log(msg.innerText);
- console.log('');
- }
- return 1;
- } else {
- console.log(document.body.querySelector('.alert > .passingAlert.bar').innerText);
- return 0;
- }
- });
- testFinished(exitCode);
- },
- 10000, // 10 second timeout
- "Test failed waiting for jasmine results on page: " + url);
- }
- });
-}
-
-function scanDirectory(path, regex) {
- var files = [];
- fs.list(path).forEach(function(file) {
- if (file.match(regex)) {
- files.push(file);
- }
- });
- return files;
-}
-
-var totalTests = 0,
- totalFailed = 0,
- totalDone = 0;
-
-function testFinished(failed) {
- if (failed) {
- totalFailed++;
- }
- totalDone++;
- if (totalDone === totalTests) {
- phantom.exit(totalFailed > 0 ? 1 : 0);
- }
-}
-
-if (system.args.length != 2 && system.args[1] != "--no-tests") {
- var files = scanDirectory("test/browser/", /^test-runner-.+\.htm$/);
- totalTests = files.length;
- console.log("found " + files.length + " tests");
- files.forEach(function(file) {
- testPage("http://localhost:8081/browser/" + file);
- });
-}
\ No newline at end of file
+++ /dev/null
-var less = {};
-
-// There originally run inside describe method. However, since they have not
-// been inside it, they run at jasmine compile time (not runtime). It all
-// worked cause less.js was in async mode and custom phantom runner had
-// different setup then grunt-contrib-jasmine. They have been created before
-// less.js run, even as they have been defined in spec.
-
-// test inline less in style tags by grabbing an assortment of less files and doing `@import`s
-var testFiles = ['charsets', 'colors', 'comments', 'css-3', 'strings', 'media', 'mixins'],
- testSheets = [];
-
-// setup style tags with less and link tags pointing to expected css output
-for (var i = 0; i < testFiles.length; i++) {
- var file = testFiles[i],
- lessPath = '/test/less/' + file + '.less',
- cssPath = '/test/css/' + file + '.css',
- lessStyle = document.createElement('style'),
- cssLink = document.createElement('link'),
- lessText = '@import "' + lessPath + '";';
-
- lessStyle.type = 'text/less';
- lessStyle.id = file;
- lessStyle.href = file;
-
- if (lessStyle.styleSheet) {
- lessStyle.styleSheet.cssText = lessText;
- } else {
- lessStyle.innerHTML = lessText;
- }
-
- cssLink.rel = 'stylesheet';
- cssLink.type = 'text/css';
- cssLink.href = cssPath;
- cssLink.id = 'expected-' + file;
-
- var head = document.getElementsByTagName('head')[0];
-
- head.appendChild(lessStyle);
- head.appendChild(cssLink);
- testSheets[i] = lessStyle;
-}
\ No newline at end of file
+++ /dev/null
-describe("less.js browser behaviour", function() {
- testLessEqualsInDocument();
-
- it("has some log messages", function() {
- expect(logMessages.length).toBeGreaterThan(0);
- });
-
- for (var i = 0; i < testFiles.length; i++) {
- var sheet = testSheets[i];
- testSheet(sheet);
- }
-});
+++ /dev/null
-less.errorReporting = 'console';
-
-describe("less.js error reporting console test", function() {
- testLessErrorsInDocument(true);
-});
\ No newline at end of file
+++ /dev/null
-var less = {
- strictUnits: true,
- strictMath: true
-};
-
+++ /dev/null
-describe("less.js error tests", function() {
- testLessErrorsInDocument();
-});
-
+++ /dev/null
-var less = {};
-less.globalVars = {
- "@global-var": "red"
-};
+++ /dev/null
-describe("less.js global vars", function() {
- testLessEqualsInDocument();
-});
+++ /dev/null
-var less = {};
-less.strictMath = false;
-less.strictUnits = false;
-
+++ /dev/null
-describe("less.js legacy tests", function() {
- testLessEqualsInDocument();
-});
+++ /dev/null
-var less = {};
-less.strictMath = true;
-less.functions = {
- add: function(a, b) {
- return new(less.tree.Dimension)(a.value + b.value);
- },
- increment: function(a) {
- return new(less.tree.Dimension)(a.value + 1);
- },
- _color: function(str) {
- if (str.value === "evil red") {
- return new(less.tree.Color)("600");
- }
- }
-};
\ No newline at end of file
+++ /dev/null
-describe("less.js main tests", function() {
- testLessEqualsInDocument();
-});
+++ /dev/null
-/* exported less */
-var less = {};
\ No newline at end of file
+++ /dev/null
-var alreadyRun = false;
-
-describe("less.js modify vars", function() {
- beforeEach(function() {
- // simulating "setUp" or "beforeAll" method
- var lessOutputObj;
- if (alreadyRun)
- return;
-
- alreadyRun = true;
-
- // wait until the sheet is compiled first time
- waitsFor(function() {
- lessOutputObj = document.getElementById("less:test-less-simple");
- return lessOutputObj !== null;
- }, "first generation of less:test-less-simple", 7000);
-
- // modify variables
- runs(function() {
- lessOutputObj.type = "not compiled yet";
- less.modifyVars({
- var1: "green",
- var2: "purple"
- });
- });
-
- // wait until variables are modified
- waitsFor(function() {
- lessOutputObj = document.getElementById("less:test-less-simple");
- return lessOutputObj !== null && lessOutputObj.type === "text/css";
- }, "second generation of less:test-less-simple", 7000);
-
- });
-
- testLessEqualsInDocument();
- it("Should log only 2 XHR requests", function() {
- var xhrLogMessages = logMessages.filter(function(item) {
- return (/XHR: Getting '/).test(item);
- });
- expect(xhrLogMessages.length).toEqual(2);
- });
-});
\ No newline at end of file
+++ /dev/null
-var less = {};
-
-less.strictUnits = true;
-less.javascriptEnabled = false;
+++ /dev/null
-describe("less.js javascript disabled error tests", function() {
- testLessErrorsInDocument();
-});
-
+++ /dev/null
-var less = {};
-less.env = "production";
-
+++ /dev/null
-describe("less.js production behaviour", function() {
- it("doesn't log any messages", function() {
- expect(logMessages.length).toEqual(0);
- });
-});
+++ /dev/null
-var less = {};
-less.relativeUrls = true;
-
+++ /dev/null
-describe("less.js browser test - relative url's", function() {
- testLessEqualsInDocument();
-});
+++ /dev/null
-var less = {};
-less.rootpath = "https://www.github.com/";
-
+++ /dev/null
-var less = {};
-less.rootpath = "https://www.github.com/cloudhead/less.js/";
-less.relativeUrls = true;
-
+++ /dev/null
-describe("less.js browser test - rootpath and relative url's", function() {
- testLessEqualsInDocument();
-});
+++ /dev/null
-describe("less.js browser test - rootpath url's", function() {
- testLessEqualsInDocument();
-});
+++ /dev/null
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="utf-8">
- <title>Jasmine Spec Runner</title>
-
- <!-- generate script tags for tests -->
- <% var generateScriptTags = function(allScripts) { allScripts.forEach(function(script){ %>
- <script src="<%= script %>"></script>
- <% }); }; %>
-
- <!-- for each test, generate CSS/LESS link tags -->
- <% scripts.src.forEach(function(fullLessName) {
- var pathParts = fullLessName.split('/');
- var fullCssName = fullLessName.replace(/less/g, 'css');
- var lessName = pathParts[pathParts.length - 1];
- var name = lessName.split('.')[0]; %>
- <!-- the tags to be generated -->
- <link id="original-less:test-less-<%= name %>" title="test-less-<%= name %>" rel="stylesheet/less" type="text/css" href="<%= fullLessName %>">
- <link id="expected-less:test-less-<%= name %>" rel="stylesheet" type="text/css" href="<%= fullCssName %>">
- <% }); %>
-
- <!-- generate grunt-contrib-jasmine link tags -->
- <% css.forEach(function(style){ %>
- <link rel="stylesheet" type="text/css" href="<%= style %>">
- <% }) %>
-
- <!-- inital grunt-contrib-jasmine scripts -->
- <% generateScriptTags([].concat(scripts.polyfills, scripts.jasmine)); %>
-
- <!-- Helpers - The less options -->
- <% generateScriptTags(scripts.helpers); %>
-
- <!-- Vendor - less.js and common code -->
- <% generateScriptTags(scripts.vendor); %>
-
- <!-- Spec -->
- <% generateScriptTags(scripts.specs); %>
-
- <!-- final grunt-contrib-jasmine scripts -->
- <% generateScriptTags([].concat(scripts.reporters, scripts.start)); %>
- </head>
-
- <body>
- <!-- content -->
- </body>
-</html>
+++ /dev/null
-@charset "UTF-8";
+++ /dev/null
-#yelow #short {
- color: #fea;
-}
-#yelow #long {
- color: #ffeeaa;
-}
-#yelow #rgba {
- color: rgba(255, 238, 170, 0.1);
-}
-#yelow #argb {
- color: #1affeeaa;
-}
-#blue #short {
- color: #00f;
-}
-#blue #long {
- color: #0000ff;
-}
-#blue #rgba {
- color: rgba(0, 0, 255, 0.1);
-}
-#blue #argb {
- color: #1a0000ff;
-}
-#alpha #hsla {
- color: rgba(61, 45, 41, 0.6);
-}
-#overflow .a {
- color: #000000;
-}
-#overflow .b {
- color: #ffffff;
-}
-#overflow .c {
- color: #ffffff;
-}
-#overflow .d {
- color: #00ff00;
-}
-#grey {
- color: #c8c8c8;
-}
-#333333 {
- color: #333333;
-}
-#808080 {
- color: #808080;
-}
-#00ff00 {
- color: #00ff00;
-}
-.lightenblue {
- color: #3333ff;
-}
-.darkenblue {
- color: #0000cc;
-}
-.unknowncolors {
- color: blue2;
- border: 2px solid superred;
-}
-.transparent {
- color: transparent;
- background-color: rgba(0, 0, 0, 0);
-}
-#alpha #fromvar {
- opacity: 0.7;
-}
-#alpha #short {
- opacity: 1;
-}
-#alpha #long {
- opacity: 1;
-}
-#alpha #rgba {
- opacity: 0.2;
-}
-#alpha #hsl {
- opacity: 1;
-}
+++ /dev/null
-/******************\
-* *
-* Comment Header *
-* *
-\******************/
-/*
-
- Comment
-
-*/
-/*
- * Comment Test
- *
- * - cloudhead (http://cloudhead.net)
- *
- */
-/* Colors
- * ------
- * #EDF8FC (background blue)
- * #166C89 (darkest blue)
- *
- * Text:
- * #333 (standard text) // A comment within a comment!
- * #1F9EC9 (standard link)
- *
- */
-/* @group Variables
-------------------- */
-#comments,
-.comments {
- /**/
- color: red;
- /* A C-style comment */
- /* A C-style comment */
- background-color: orange;
- font-size: 12px;
- /* lost comment */
- content: "content";
- border: 1px solid black;
- padding: 0;
- margin: 2em;
-}
-/* commented out
- #more-comments {
- color: grey;
- }
-*/
-.selector,
-.lots,
-.comments {
- color: #808080, /* blue */ #ffa500;
- -webkit-border-radius: 2px /* webkit only */;
- -moz-border-radius: 8px /* moz only with operation */;
-}
-.test {
- color: 1px;
-}
-#last {
- color: #0000ff;
-}
-/* */
-/* { */
-/* */
-/* */
-/* */
-#div {
- color: #A33;
-}
-/* } */
+++ /dev/null
-#colours{color1:#fea;color2:#fea;color3:rgba(255,238,170,0.1);string:"#ffeeaa";/*! but not this type
- Note preserved whitespace
- */}dimensions{val:.1px;val:0;val:4cm;val:.2;val:5;angles-must-have-unit:0deg;durations-must-have-unit:0s;length-doesnt-have-unit:0;width:auto\9}@page{marks:none;@top-left-corner{vertical-align:top}@top-left{vertical-align:top}}
\ No newline at end of file
+++ /dev/null
-.comma-delimited {
- text-shadow: -1px -1px 1px #ff0000, 6px 5px 5px #ffff00;
- -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset, 0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
- -webkit-transform: rotate(-0.0000000001deg);
-}
-@font-face {
- font-family: Headline;
- unicode-range: U+??????, U+0???, U+0-7F, U+A5;
-}
-.other {
- -moz-transform: translate(0, 11em) rotate(-90deg);
- transform: rotateX(45deg);
-}
-.item[data-cra_zy-attr1b-ut3=bold] {
- font-weight: bold;
-}
-p:not([class*="lead"]) {
- color: black;
-}
-input[type="text"].class#id[attr=32]:not(1) {
- color: white;
-}
-div#id.class[a=1][b=2].class:not(1) {
- color: white;
-}
-ul.comma > li:not(:only-child)::after {
- color: white;
-}
-ol.comma > li:nth-last-child(2)::after {
- color: white;
-}
-li:nth-child(4n+1),
-li:nth-child(-5n),
-li:nth-child(-n+2) {
- color: white;
-}
-a[href^="http://"] {
- color: black;
-}
-a[href$="http://"] {
- color: black;
-}
-form[data-disabled] {
- color: black;
-}
-p::before {
- color: black;
-}
-#issue322 {
- -webkit-animation: anim2 7s infinite ease-in-out;
-}
-@-webkit-keyframes frames {
- 0% {
- border: 1px;
- }
- 5.5% {
- border: 2px;
- }
- 100% {
- border: 3px;
- }
-}
-@keyframes fontbulger1 {
- to {
- font-size: 15px;
- }
- from,
- to {
- font-size: 12px;
- }
- 0%,
- 100% {
- font-size: 12px;
- }
-}
-.units {
- font: 1.2rem/2rem;
- font: 8vw/9vw;
- font: 10vh/12vh;
- font: 12vm/15vm;
- font: 12vmin/15vmin;
- font: 1.2ch/1.5ch;
-}
-@supports ( box-shadow: 2px 2px 2px black ) or
- ( -moz-box-shadow: 2px 2px 2px black ) {
- .outline {
- box-shadow: 2px 2px 2px black;
- -moz-box-shadow: 2px 2px 2px black;
- }
-}
-@-x-document url-prefix(""github.com"") {
- h1 {
- color: red;
- }
-}
-@viewport {
- font-size: 10px;
-}
-@namespace foo url(http://www.example.com);
-foo|h1 {
- color: blue;
-}
-foo|* {
- color: yellow;
-}
-|h1 {
- color: red;
-}
-*|h1 {
- color: green;
-}
-h1 {
- color: green;
-}
-.upper-test {
- UpperCaseProperties: allowed;
-}
-@host {
- div {
- display: block;
- }
-}
-::distributed(input::placeholder) {
- color: #b3b3b3;
-}
+++ /dev/null
-.escape\|random\|char {
- color: red;
-}
-.mixin\!tUp {
- font-weight: bold;
-}
-.\34 04 {
- background: red;
-}
-.\34 04 strong {
- color: #ff00ff;
- font-weight: bold;
-}
-.trailingTest\+ {
- color: red;
-}
-/* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */
-\62\6c\6f \63 \6B \0071 \000075o\74 e {
- color: silver;
-}
-[ng\:cloak],
-ng\:form {
- display: none;
-}
+++ /dev/null
-.light {
- color: green;
-}
-.see-the {
- color: orange;
-}
-.hide-the {
- color: green;
-}
-.multiple-conditions-1 {
- color: red;
-}
-.inheritance .test {
- color: black;
-}
-.inheritance:hover {
- color: pink;
-}
+++ /dev/null
-@charset "utf-8";
-div {
- color: black;
-}
-div {
- width: 99%;
-}
-* {
- min-width: 45em;
-}
-h1,
-h2 > a > p,
-h3 {
- color: unset;
-}
-div.class {
- color: blue;
-}
-div#id {
- color: green;
-}
-.class#id {
- color: purple;
-}
-.one.two.three {
- color: grey;
-}
-@media print {
- * {
- font-size: 3em;
- }
-}
-@media screen {
- * {
- font-size: 10px;
- }
-}
-@font-face {
- font-family: 'Garamond Pro';
-}
-a:hover,
-a:link {
- color: #999;
-}
-p,
-p:first-child {
- text-transform: none;
-}
-q:lang(no) {
- quotes: none;
-}
-p + h1 {
- font-size: 2.2em;
-}
-#shorthands {
- border: 1px solid #000;
- font: 12px/16px Arial;
- font: 100%/16px Arial;
- margin: 1px 0;
- padding: 0 auto;
-}
-#more-shorthands {
- margin: 0;
- padding: 1px 0 2px 0;
- font: normal small / 20px 'Trebuchet MS', Verdana, sans-serif;
- font: 0/0 a;
- border-radius: 5px / 10px;
-}
-.misc {
- -moz-border-radius: 2px;
- display: -moz-inline-stack;
- width: .1em;
- background-color: #009998;
- background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), to(#0000ff));
- filter: alpha(opacity=100);
- width: auto\9;
-}
-.misc .nested-multiple {
- multiple-semi-colons: yes;
-}
-#important {
- color: red !important;
- width: 100%!important;
- height: 20px ! important;
-}
-@font-face {
- font-family: font-a;
-}
-@font-face {
- font-family: font-b;
-}
-.æøå {
- margin: 0;
-}
+++ /dev/null
-@charset "UTF-8";
-/* line 3, {pathimport}test.less */
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000033}}
-/* @charset "ISO-8859-1"; */
-/* line 23, {pathimport}test.less */
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}}
-.tst3 {
- color: grey;
-}
-/* line 15, {path}linenumbers.less */
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000315}}
-.test1 {
- color: black;
-}
-/* line 6, {path}linenumbers.less */
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\000036}}
-.test2 {
- color: red;
-}
-@media all {
- /* line 5, {pathimport}test.less */
- @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000035}}
- .tst {
- color: black;
- }
-}
-@media all and screen {
- /* line 7, {pathimport}test.less */
- @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000037}}
- .tst {
- color: red;
- }
- /* line 9, {pathimport}test.less */
- @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000039}}
- .tst .tst3 {
- color: white;
- }
-}
-/* line 18, {pathimport}test.less */
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000318}}
-.tst2 {
- color: white;
-}
+++ /dev/null
-@charset "UTF-8";
-/* line 3, {pathimport}test.less */
-/* @charset "ISO-8859-1"; */
-/* line 23, {pathimport}test.less */
-.tst3 {
- color: grey;
-}
-/* line 15, {path}linenumbers.less */
-.test1 {
- color: black;
-}
-/* line 6, {path}linenumbers.less */
-.test2 {
- color: red;
-}
-@media all {
- /* line 5, {pathimport}test.less */
- .tst {
- color: black;
- }
-}
-@media all and screen {
- /* line 7, {pathimport}test.less */
- .tst {
- color: red;
- }
- /* line 9, {pathimport}test.less */
- .tst .tst3 {
- color: white;
- }
-}
-/* line 18, {pathimport}test.less */
-.tst2 {
- color: white;
-}
+++ /dev/null
-@charset "UTF-8";
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000033}}
-/* @charset "ISO-8859-1"; */
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000323}}
-.tst3 {
- color: grey;
-}
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\0000315}}
-.test1 {
- color: black;
-}
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathesc}linenumbers\.less}line{font-family:\000036}}
-.test2 {
- color: red;
-}
-@media all {
- @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000035}}
- .tst {
- color: black;
- }
-}
-@media all and screen {
- @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000037}}
- .tst {
- color: red;
- }
- @media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\000039}}
- .tst .tst3 {
- color: white;
- }
-}
-@media -sass-debug-info{filename{font-family:file\:\/\/{pathimportesc}test\.less}line{font-family:\0000318}}
-.tst2 {
- color: white;
-}
+++ /dev/null
-.a,
-.b,
-.c {
- color: black;
-}
-.f,
-.e,
-.d {
- color: black;
-}
-.g.h,
-.i.j.h,
-.k.j.h {
- color: black;
-}
-.i.j,
-.k.j {
- color: white;
-}
-.l,
-.m,
-.n,
-.o,
-.p,
-.q,
-.r,
-.s,
-.t {
- color: black;
-}
-.u,
-.v.u.v {
- color: black;
-}
-.w,
-.v.w.v {
- color: black;
-}
-.x,
-.y,
-.z {
- color: x;
-}
-.y,
-.z,
-.x {
- color: y;
-}
-.z,
-.x,
-.y {
- color: z;
-}
-.va,
-.vb,
-.vc {
- color: black;
-}
-.vb,
-.vc {
- color: white;
-}
-@media tv {
- .ma,
- .mb,
- .mc {
- color: black;
- }
- .md,
- .ma,
- .mb,
- .mc {
- color: white;
- }
-}
-@media tv and plasma {
- .me,
- .mf {
- background: red;
- }
-}
+++ /dev/null
-.clearfix,
-.foo,
-.bar {
- *zoom: 1;
-}
-.clearfix:after,
-.foo:after,
-.bar:after {
- content: '';
- display: block;
- clear: both;
- height: 0;
-}
-.foo {
- color: red;
-}
-.bar {
- color: blue;
-}
+++ /dev/null
-.replace.replace .replace,
-.c.replace + .replace .replace,
-.replace.replace .c,
-.c.replace + .replace .c,
-.rep_ace {
- prop: copy-paste-replace;
-}
-.a .b .c {
- prop: not_effected;
-}
-.a,
-.effected {
- prop: is_effected;
-}
-.a .b {
- prop: not_effected;
-}
-.a .b.c {
- prop: not_effected;
-}
-.c .b .a,
-.a .b .a,
-.c .a .a,
-.a .a .a,
-.c .b .c,
-.a .b .c,
-.c .a .c,
-.a .a .c {
- prop: not_effected;
-}
-.e.e,
-.dbl {
- prop: extend-double;
-}
-.e.e:hover {
- hover: not-extended;
-}
+++ /dev/null
-.ext1 .ext2,
-.all .ext2 {
- background: black;
-}
-@media tv {
- .ext1 .ext3,
- .tv-lowres .ext3,
- .all .ext3 {
- color: white;
- }
- .tv-lowres {
- background: blue;
- }
-}
-@media tv and hires {
- .ext1 .ext4,
- .tv-hires .ext4,
- .all .ext4 {
- color: green;
- }
- .tv-hires {
- background: red;
- }
-}
+++ /dev/null
-.sidebar,
-.sidebar2,
-.type1 .sidebar3,
-.type2.sidebar4 {
- width: 300px;
- background: red;
-}
-.sidebar .box,
-.sidebar2 .box,
-.type1 .sidebar3 .box,
-.type2.sidebar4 .box {
- background: #FFF;
- border: 1px solid #000;
- margin: 10px 0;
-}
-.sidebar2 {
- background: blue;
-}
-.type1 .sidebar3 {
- background: green;
-}
-.type2.sidebar4 {
- background: red;
-}
-.button,
-.submit {
- color: black;
-}
-.button:hover,
-.submit:hover {
- color: white;
-}
-.button2 :hover {
- nested: white;
-}
-.button2 :hover {
- notnested: black;
-}
-.amp-test-h,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-a.amp-test-d.amp-test-b.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-a.amp-test-e.amp-test-g,
-.amp-test-f.amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e + .amp-test-c .amp-test-b.amp-test-d.amp-test-b.amp-test-e.amp-test-g {
- test: extended by masses of selectors;
-}
+++ /dev/null
-.error,
-.badError {
- border: 1px #f00;
- background: #fdd;
-}
-.error.intrusion,
-.badError.intrusion {
- font-size: 1.3em;
- font-weight: bold;
-}
-.intrusion .error,
-.intrusion .badError {
- display: none;
-}
-.badError {
- border-width: 3px;
-}
-.foo .bar,
-.foo .baz,
-.ext1 .ext2 .bar,
-.ext1 .ext2 .baz,
-.ext3 .bar,
-.ext3 .baz,
-.ext4 .bar,
-.ext4 .baz {
- display: none;
-}
-div.ext5,
-.ext6 > .ext5,
-div.ext7,
-.ext6 > .ext7 {
- width: 100px;
-}
-.ext,
-.a .c,
-.b .c {
- test: 1;
-}
-.a,
-.b {
- test: 2;
-}
-.a .c,
-.b .c {
- test: 3;
-}
-.a .c .d,
-.b .c .d {
- test: 4;
-}
-.replace.replace .replace,
-.c.replace + .replace .replace,
-.replace.replace .c,
-.c.replace + .replace .c,
-.rep_ace.rep_ace .rep_ace,
-.c.rep_ace + .rep_ace .rep_ace,
-.rep_ace.rep_ace .c,
-.c.rep_ace + .rep_ace .c {
- prop: copy-paste-replace;
-}
-.attributes [data="test"],
-.attributes .attributes .attribute-test {
- extend: attributes;
-}
-.attributes [data],
-.attributes .attributes .attribute-test2 {
- extend: attributes2;
-}
-.attributes [data="test3"],
-.attributes .attributes .attribute-test {
- extend: attributes2;
-}
-.header .header-nav,
-.footer .footer-nav {
- background: red;
-}
-.header .header-nav:before,
-.footer .footer-nav:before {
- background: blue;
-}
+++ /dev/null
-.error,
-.badError {
- border: 1px #f00;
- background: #fdd;
-}
-.error.intrusion,
-.badError.intrusion {
- font-size: 1.3em;
- font-weight: bold;
-}
-.intrusion .error,
-.intrusion .badError {
- display: none;
-}
-.badError {
- border-width: 3px;
-}
-.foo .bar,
-.foo .baz,
-.ext1 .ext2 .bar,
-.ext1 .ext2 .baz,
-.ext3 .bar,
-.ext3 .baz,
-.foo .ext3,
-.ext4 .bar,
-.ext4 .baz,
-.foo .ext4 {
- display: none;
-}
-div.ext5,
-.ext6 > .ext5,
-div.ext7,
-.ext6 > .ext7 {
- width: 100px;
-}
-.ext8.ext9,
-.fuu {
- result: add-foo;
-}
-.ext8 .ext9,
-.ext8 + .ext9,
-.ext8 > .ext9,
-.buu,
-.zap,
-.zoo {
- result: bar-matched;
-}
-.ext8.nomatch {
- result: none;
-}
-.ext8 .ext9,
-.buu {
- result: match-nested-bar;
-}
-.ext8.ext9,
-.fuu {
- result: match-nested-foo;
-}
-.aa,
-.cc {
- color: black;
-}
-.aa .dd,
-.aa .ee {
- background: red;
-}
-.bb,
-.cc,
-.ee,
-.ff {
- background: red;
-}
-.bb .bb,
-.ff .ff {
- color: black;
-}
+++ /dev/null
-.multiunit {
- length: 6;
- extract: abc "abc" 1 1px 1% #112233;
-}
-.incorrect-index {
- v1: extract(a b c, 5);
- v2: extract(a, b, c, -2);
-}
-.scalar {
- var-value: variable;
- var-length: 1;
- ill-index: extract(variable, 2);
- name-value: name;
- string-value: "string";
- number-value: 12345678;
- color-value: #0000ff;
- rgba-value: rgba(80, 160, 240, 0.67);
- empty-value: ;
- name-length: 1;
- string-length: 1;
- number-length: 1;
- color-length: 1;
- rgba-length: 1;
- empty-length: 1;
-}
-.mixin-arguments-1 {
- length: 4;
- extract: c | b | a;
-}
-.mixin-arguments-2 {
- length: 4;
- extract: c | b | a;
-}
-.mixin-arguments-3 {
- length: 4;
- extract: c | b | a;
-}
-.mixin-arguments-4 {
- length: 0;
- extract: extract(, 2) | extract(, 1);
-}
-.mixin-arguments-2 {
- length: 4;
- extract: c | b | a;
-}
-.mixin-arguments-3 {
- length: 4;
- extract: c | b | a;
-}
-.mixin-arguments-4 {
- length: 3;
- extract: c | b;
-}
-.mixin-arguments-2 {
- length: 4;
- extract: 3 | 2 | 1;
-}
-.mixin-arguments-3 {
- length: 4;
- extract: 3 | 2 | 1;
-}
-.mixin-arguments-4 {
- length: 3;
- extract: 3 | 2;
-}
-.md-space-comma {
- length-1: 3;
- extract-1: 1 2 3;
- length-2: 3;
- extract-2: 2;
-}
-.md-space-comma-as-args-2 {
- length: 3;
- extract: "x" "y" "z" | 1 2 3 | a b c;
-}
-.md-space-comma-as-args-3 {
- length: 3;
- extract: "x" "y" "z" | 1 2 3 | a b c;
-}
-.md-space-comma-as-args-4 {
- length: 2;
- extract: "x" "y" "z" | 1 2 3;
-}
-.md-cat-space-comma {
- length-1: 3;
- extract-1: 1 2 3;
- length-2: 3;
- extract-2: 2;
-}
-.md-cat-space-comma-as-args-2 {
- length: 3;
- extract: "x" "y" "z" | 1 2 3 | a b c;
-}
-.md-cat-space-comma-as-args-3 {
- length: 3;
- extract: "x" "y" "z" | 1 2 3 | a b c;
-}
-.md-cat-space-comma-as-args-4 {
- length: 2;
- extract: "x" "y" "z" | 1 2 3;
-}
-.md-cat-comma-space {
- length-1: 3;
- extract-1: 1, 2, 3;
- length-2: 3;
- extract-2: 2;
-}
-.md-cat-comma-space-as-args-1 {
- length: 3;
- extract: "x", "y", "z" | 1, 2, 3 | a, b, c;
-}
-.md-cat-comma-space-as-args-2 {
- length: 3;
- extract: "x", "y", "z" | 1, 2, 3 | a, b, c;
-}
-.md-cat-comma-space-as-args-3 {
- length: 3;
- extract: "x", "y", "z" | 1, 2, 3 | a, b, c;
-}
-.md-cat-comma-space-as-args-4 {
- length: 0;
- extract: extract(, 2) | extract(, 1);
-}
-.md-3D {
- length-1: 2;
- extract-1: a b c d, 1 2 3 4;
- length-2: 2;
- extract-2: 5 6 7 8;
- length-3: 4;
- extract-3: 7;
- length-4: 1;
- extract-4: 8;
-}
+++ /dev/null
-#functions {
- color: #660000;
- width: 16;
- height: undefined("self");
- border-width: 5;
- variable: 11;
- background: linear-gradient(#000000, #ffffff);
-}
-#built-in {
- escaped: -Some::weird(#thing, y);
- lighten: #ffcccc;
- darken: #330000;
- saturate: #203c31;
- desaturate: #29332f;
- greyscale: #2e2e2e;
- hsl-clamp: #ffffff;
- spin-p: #bf6a40;
- spin-n: #bf4055;
- luma-white: 100%;
- luma-black: 0%;
- luma-black-alpha: 0%;
- luma-red: 21%;
- luma-green: 72%;
- luma-blue: 7%;
- luma-yellow: 93%;
- luma-cyan: 79%;
- luma-white-alpha: 50%;
- contrast-filter: contrast(30%);
- saturate-filter: saturate(5%);
- contrast-white: #000000;
- contrast-black: #ffffff;
- contrast-red: #ffffff;
- contrast-green: #000000;
- contrast-blue: #ffffff;
- contrast-yellow: #000000;
- contrast-cyan: #000000;
- contrast-light: #111111;
- contrast-dark: #eeeeee;
- contrast-wrongorder: #111111;
- contrast-light-thresh: #111111;
- contrast-dark-thresh: #eeeeee;
- contrast-high-thresh: #eeeeee;
- contrast-low-thresh: #111111;
- contrast-light-thresh-per: #111111;
- contrast-dark-thresh-per: #eeeeee;
- contrast-high-thresh-per: #eeeeee;
- contrast-low-thresh-per: #111111;
- format: "rgb(32, 128, 64)";
- format-string: "hello world";
- format-multiple: "hello earth 2";
- format-url-encode: "red is %23ff0000";
- eformat: rgb(32, 128, 64);
- unitless: 12;
- unit: 14em;
- hue: 98;
- saturation: 12%;
- lightness: 95%;
- hsvhue: 98;
- hsvsaturation: 12%;
- hsvvalue: 95%;
- red: 255;
- green: 255;
- blue: 255;
- rounded: 11;
- rounded-two: 10.67;
- roundedpx: 3px;
- roundedpx-three: 3.333px;
- rounded-percentage: 10%;
- ceil: 11px;
- floor: 12px;
- sqrt: 5px;
- pi: 3.141592653589793;
- mod: 2m;
- abs: 4%;
- tan: 0.9004040442978399;
- sin: 0.17364817766693033;
- cos: 0.8438539587324921;
- atan: 0.1rad;
- atan: 34.00000000000001deg;
- atan: 45.00000000000001deg;
- pow: 64px;
- pow: 64;
- pow: 27;
- min: 0;
- min: min("junk", 5);
- min: 3pt;
- max: 3;
- max: max(8%, 1cm);
- percentage: 20%;
- color: #ff0011;
- tint: #898989;
- tint-full: #ffffff;
- tint-percent: #898989;
- shade: #686868;
- shade-full: #000000;
- shade-percent: #686868;
- fade-out: rgba(255, 0, 0, 0.95);
- fade-in: rgba(255, 0, 0, 0.9500000000000001);
- hsv: #4d2926;
- hsva: rgba(77, 40, 38, 0.2);
- mix: #ff3300;
- mix-0: #ffff00;
- mix-100: #ff0000;
- mix-weightless: #ff8000;
- mixt: rgba(255, 0, 0, 0.5);
-}
-#built-in .is-a {
- color: true;
- color1: true;
- color2: true;
- color3: true;
- keyword: true;
- number: true;
- string: true;
- pixel: true;
- percent: true;
- em: true;
- cat: true;
-}
-#alpha {
- alpha: rgba(153, 94, 51, 0.6);
- alpha2: 0.5;
- alpha3: 0;
-}
-#blendmodes {
- multiply: #ed0000;
- screen: #f600f6;
- overlay: #ed0000;
- softlight: #ff0000;
- hardlight: #0000ed;
- difference: #f600f6;
- exclusion: #f600f6;
- average: #7b007b;
- negation: #d73131;
-}
-#extract-and-length {
- extract: 3 2 1 C B A;
- length: 6;
-}
+++ /dev/null
-.nav {
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity=20);
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr="#000000", GradientType=0);
-}
-.evalTest1 {
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity=30);
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity=5);
-}
+++ /dev/null
-this isn't very valid CSS.
-@media (min-width: 600px) {
- #css { color: yellow; }
-
-}
+++ /dev/null
-body {
- width: 100%;
-}
-.a {
- var: test;
-}
+++ /dev/null
-#import {
- color: #ff0000;
-}
-body {
- width: 100%;
-}
-.test-f {
- height: 10px;
-}
-body {
- width: 100%;
-}
-.test-f {
- height: 10px;
-}
+++ /dev/null
-/*
- The media statement above is invalid (no selector)
- We should ban invalid media queries with properties and no selector?
-*/
-.visible {
- color: red;
-}
-.visible .c {
- color: green;
-}
-.visible {
- color: green;
-}
-.visible:hover {
- color: green;
-}
-.visible {
- color: green;
-}
-.only-with-visible + .visible,
-.visible + .only-with-visible,
-.visible + .visible {
- color: green;
-}
-.only-with-visible + .visible .sub,
-.visible + .only-with-visible .sub,
-.visible + .visible .sub {
- color: green;
-}
-.b {
- color: red;
- color: green;
-}
-.b .c {
- color: green;
-}
-.b:hover {
- color: green;
-}
-.b {
- color: green;
-}
-.b + .b {
- color: green;
-}
-.b + .b .sub {
- color: green;
-}
-.y {
- pulled-in: yes;
-}
-/* comment pulled in */
-.visible {
- extend: test;
-}
+++ /dev/null
-@import url(http://fonts.googleapis.com/css?family=Open+Sans);
-@import url(/absolute/something.css) screen and (color) and (max-width: 600px);
-@import url("//ha.com/file.css") (min-width: 100px);
-#import-test {
- height: 10px;
- color: #ff0000;
- width: 10px;
- height: 30%;
-}
-@media screen and (max-width: 600px) {
- body {
- width: 100%;
- }
-}
-#import {
- color: #ff0000;
-}
-.mixin {
- height: 10px;
- color: #ff0000;
-}
-@media screen and (max-width: 601px) {
- #css {
- color: yellow;
- }
-}
-@media screen and (max-width: 602px) {
- body {
- width: 100%;
- }
-}
-@media screen and (max-width: 603px) {
- #css {
- color: yellow;
- }
-}
+++ /dev/null
-.eval {
- js: 42;
- js: 2;
- js: "hello world";
- js: 1, 2, 3;
- title: "string";
- ternary: true;
- multiline: 2;
-}
-.scope {
- var: 42;
- escaped: 7px;
-}
-.vars {
- width: 8;
-}
-.escape-interpol {
- width: hello world;
-}
-.arrays {
- ary: "1, 2, 3";
- ary1: "1, 2, 3";
-}
+++ /dev/null
-.lazy-eval {
- width: 100%;
-}
+++ /dev/null
-@media (-o-min-device-pixel-ratio: 2/1) {
- .test-math-and-units {
- font: ignores 0/0 rules;
- test-division: 7em;
- simple: 2px;
- }
-}
+++ /dev/null
-@media print {
- .class {
- color: blue;
- }
- .class .sub {
- width: 42;
- }
- .top,
- header > h1 {
- color: #444444;
- }
-}
-@media screen {
- body {
- max-width: 480;
- }
-}
-@media all and (device-aspect-ratio: 16 / 9) {
- body {
- max-width: 800px;
- }
-}
-@media all and (orientation: portrait) {
- aside {
- float: none;
- }
-}
-@media handheld and (min-width: 42), screen and (min-width: 20em) {
- body {
- max-width: 480px;
- }
-}
-@media print {
- body {
- padding: 20px;
- }
- body header {
- background-color: red;
- }
-}
-@media print and (orientation: landscape) {
- body {
- margin-left: 20px;
- }
-}
-@media screen {
- .sidebar {
- width: 300px;
- }
-}
-@media screen and (orientation: landscape) {
- .sidebar {
- width: 500px;
- }
-}
-@media a and b {
- .first .second .third {
- width: 300px;
- }
- .first .second .fourth {
- width: 3;
- }
-}
-@media a and b and c {
- .first .second .third {
- width: 500px;
- }
-}
-@media a, b and c {
- body {
- width: 95%;
- }
-}
-@media a and x, b and c and x, a and y, b and c and y {
- body {
- width: 100%;
- }
-}
-.a {
- background: black;
-}
-@media handheld {
- .a {
- background: white;
- }
-}
-@media handheld and (max-width: 100px) {
- .a {
- background: red;
- }
-}
-.b {
- background: black;
-}
-@media handheld {
- .b {
- background: white;
- }
-}
-@media handheld and (max-width: 200px) {
- .b {
- background: red;
- }
-}
-@media only screen and (max-width: 200px) {
- body {
- width: 480px;
- }
-}
-@media print {
- @page :left {
- margin: 0.5cm;
- }
- @page :right {
- margin: 0.5cm;
- }
- @page Test:first {
- margin: 1cm;
- }
- @page :first {
- size: 8.5in 11in;
-
- @top-left {
- margin: 1cm;
- }
- @top-left-corner {
- margin: 1cm;
- }
- @top-center {
- margin: 1cm;
- }
- @top-right {
- margin: 1cm;
- }
- @top-right-corner {
- margin: 1cm;
- }
- @bottom-left {
- margin: 1cm;
- }
- @bottom-left-corner {
- margin: 1cm;
- }
- @bottom-center {
- margin: 1cm;
- }
- @bottom-right {
- margin: 1cm;
- }
- @bottom-right-corner {
- margin: 1cm;
- }
- @left-top {
- margin: 1cm;
- }
- @left-middle {
- margin: 1cm;
- }
- @left-bottom {
- margin: 1cm;
- }
- @right-top {
- margin: 1cm;
- }
- @right-middle {
- content: "Page " counter(page);
- }
- @right-bottom {
- margin: 1cm;
- }
- }
-}
-@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) {
- .b {
- background: red;
- }
-}
-body {
- background: red;
-}
-@media (max-width: 500px) {
- body {
- background: green;
- }
-}
-@media (max-width: 1000px) {
- body {
- background: red;
- background: blue;
- }
-}
-@media (max-width: 1000px) and (max-width: 500px) {
- body {
- background: green;
- }
-}
-@media (max-width: 1200px) {
- /* a comment */
-}
-@media (max-width: 1200px) and (max-width: 900px) {
- body {
- font-size: 11px;
- }
-}
-@media (min-width: 480px) {
- .nav-justified > li {
- display: table-cell;
- }
-}
-@media (min-width: 768px) and (min-width: 480px) {
- .menu > li {
- display: table-cell;
- }
-}
-@media all and tv {
- .all-and-tv-variables {
- var: all-and-tv;
- }
-}
+++ /dev/null
-.test1 {
- transform: rotate(90deg), skew(30deg), scale(2, 4);
-}
-.test2 {
- transform: rotate(90deg), skew(30deg);
- transform: scaleX(45deg);
-}
-.test3 {
- transform: scaleX(45deg);
- background: url(data://img1.png);
-}
-.test4 {
- transform: rotate(90deg), skew(30deg);
- transform: scale(2, 4) !important;
-}
-.test5 {
- transform: rotate(90deg), skew(30deg);
- transform: scale(2, 4) !important;
-}
-.test6 {
- transform: scale(2, 4);
-}
+++ /dev/null
-#hidden {
- color: transparent;
-}
-#hidden1 {
- color: transparent;
-}
-.two-args {
- color: blue;
- width: 10px;
- height: 99%;
- border: 2px dotted #000000;
-}
-.one-arg {
- width: 15px;
- height: 49%;
-}
-.no-parens {
- width: 5px;
- height: 49%;
-}
-.no-args {
- width: 5px;
- height: 49%;
-}
-.var-args {
- width: 45;
- height: 17%;
-}
-.multi-mix {
- width: 10px;
- height: 29%;
- margin: 4;
- padding: 5;
-}
-body {
- padding: 30px;
- color: #ff0000;
-}
-.scope-mix {
- width: 8;
-}
-.content {
- width: 600px;
-}
-.content .column {
- margin: 600px;
-}
-#same-var-name {
- radius: 5px;
-}
-#var-inside {
- width: 10px;
-}
-.arguments {
- border: 1px solid #000000;
- width: 1px;
-}
-.arguments2 {
- border: 0px;
- width: 0px;
-}
-.arguments3 {
- border: 0px;
- width: 0px;
-}
-.arguments4 {
- border: 0 1 2 3 4;
- rest: 1 2 3 4;
- width: 0;
-}
-.edge-case {
- border: "{";
- width: "{";
-}
-.slash-vs-math {
- border-radius: 2px/5px;
- border-radius: 5px/10px;
- border-radius: 6px;
-}
-.comma-vs-semi-colon {
- one: a;
- two: b, c;
- one: d, e;
- two: f;
- one: g;
- one: h;
- one: i;
- one: j;
- one: k;
- two: l;
- one: m, n;
- one: o, p;
- two: q;
- one: r, s;
- two: t;
-}
-#named-conflict {
- four: a, 11, 12, 13;
- four: a, 21, 22, 23;
-}
-.test-mixin-default-arg {
- defaults: 1px 1px 1px;
- defaults: 2px 2px 2px;
-}
-.selector {
- margin: 2, 2, 2, 2;
-}
-.selector2 {
- margin: 2, 2, 2, 2;
-}
-.selector3 {
- margin: 4;
-}
+++ /dev/null
-.class {
- width: 99px;
-}
-.overwrite {
- width: 99px;
-}
-.nested .class {
- width: 5px;
-}
+++ /dev/null
-.light1 {
- color: white;
- margin: 1px;
-}
-.light2 {
- color: black;
- margin: 1px;
-}
-.max1 {
- width: 6;
-}
-.max2 {
- width: 8;
-}
-.glob1 {
- margin: auto auto;
-}
-.ops1 {
- height: gt-or-eq;
- height: lt-or-eq;
- height: lt-or-eq-alias;
-}
-.ops2 {
- height: gt-or-eq;
- height: not-eq;
-}
-.ops3 {
- height: lt-or-eq;
- height: lt-or-eq-alias;
- height: not-eq;
-}
-.default1 {
- content: default;
-}
-.test1 {
- content: "true.";
-}
-.test2 {
- content: "false.";
-}
-.test3 {
- content: "false.";
-}
-.test4 {
- content: "false.";
-}
-.test5 {
- content: "false.";
-}
-.bool1 {
- content: true and true;
- content: true;
- content: false, true;
- content: false and true and true, true;
- content: false, true and true;
- content: false, false, true;
- content: false, true and true and true, false;
- content: not false;
- content: not false and false, not false;
-}
-.equality-units {
- test: pass;
-}
-.colorguardtest {
- content: is #ff0000;
- content: is not #0000ff its #ff0000;
- content: is not #0000ff its #800080;
-}
-.stringguardtest {
- content: is theme1;
- content: is not theme2;
- content: is theme1 no quotes;
-}
-#tryNumberPx {
- catch: all;
- declare: 4;
- declare: 4px;
-}
-.call-lock-mixin .call-inner-lock-mixin {
- a: 1;
- x: 1;
-}
+++ /dev/null
-.class {
- border: 1;
- boxer: 1;
- border-width: 1;
- border: 2 !important;
- boxer: 2 !important;
- border-width: 2 !important;
- border: 3;
- boxer: 3;
- border-width: 3;
- border: 4 !important;
- boxer: 4 !important;
- border-width: 4 !important;
- border: 5;
- boxer: 5;
- border-width: 5;
- border: 0 !important;
- boxer: 0 !important;
- border-width: 0 !important;
- border: 9 !important;
- border: 9;
- boxer: 9;
- border-width: 9;
-}
-.class .inner {
- test: 1;
-}
-.class .inner {
- test: 2 !important;
-}
-.class .inner {
- test: 3;
-}
-.class .inner {
- test: 4 !important;
-}
-.class .inner {
- test: 5;
-}
-.class .inner {
- test: 0 !important;
-}
-.class .inner {
- test: 9;
-}
+++ /dev/null
-.named-arg {
- color: blue;
- width: 5px;
- height: 99%;
- args: 1px 100%;
- text-align: center;
-}
-.class {
- width: 5px;
- height: 19%;
- args: 1px 20%;
-}
-.all-args-wrong-args {
- width: 10px;
- height: 9%;
- args: 2px 10%;
-}
-.named-args2 {
- width: 15px;
- height: 49%;
- color: #646464;
-}
-.named-args3 {
- width: 5px;
- height: 29%;
- color: #123456;
-}
+++ /dev/null
-.class .inner {
- height: 300;
-}
-.class .inner .innest {
- width: 30;
- border-width: 60;
-}
-.class2 .inner {
- height: 600;
-}
-.class2 .inner .innest {
- width: 60;
- border-width: 120;
-}
+++ /dev/null
-.zero {
- variadic: true;
- zero: 0;
- one: 1;
- two: 2;
- three: 3;
-}
-.one {
- variadic: true;
- one: 1;
- one-req: 1;
- two: 2;
- three: 3;
-}
-.two {
- variadic: true;
- two: 2;
- three: 3;
-}
-.three {
- variadic: true;
- three-req: 3;
- three: 3;
-}
-.left {
- left: 1;
-}
-.right {
- right: 1;
-}
-.border-right {
- color: black;
- border-right: 4px;
-}
-.border-left {
- color: black;
- border-left: 4px;
-}
-.only-right {
- right: 33;
-}
-.only-left {
- left: 33;
-}
-.left-right {
- both: 330;
-}
+++ /dev/null
-.mixin {
- border: 1px solid black;
-}
-.mixout {
- border-color: orange;
-}
-.borders {
- border-style: dashed;
-}
-#namespace .borders {
- border-style: dotted;
-}
-#namespace .biohazard {
- content: "death";
-}
-#namespace .biohazard .man {
- color: transparent;
-}
-#theme > .mixin {
- background-color: grey;
-}
-#container {
- color: black;
- border: 1px solid black;
- border-color: orange;
- background-color: grey;
-}
-#header .milk {
- color: white;
- border: 1px solid black;
- background-color: grey;
-}
-#header #cookie {
- border-style: dashed;
-}
-#header #cookie .chips {
- border-style: dotted;
-}
-#header #cookie .chips .calories {
- color: black;
- border: 1px solid black;
- border-color: orange;
- background-color: grey;
-}
-.secure-zone {
- color: transparent;
-}
-.direct {
- border-style: dotted;
-}
-.bo,
-.bar {
- width: 100%;
-}
-.bo {
- border: 1px;
-}
-.ar.bo.ca {
- color: black;
-}
-.jo.ki {
- background: none;
-}
-.amp.support {
- color: orange;
-}
-.amp.support .higher {
- top: 0px;
-}
-.amp.support.deeper {
- height: auto;
-}
-.extended {
- width: 100%;
- border: 1px;
- background: none;
- color: orange;
- top: 0px;
- height: auto;
-}
-.extended .higher {
- top: 0px;
-}
-.extended.deeper {
- height: auto;
-}
-.do .re .mi .fa .sol .la .si {
- color: cyan;
-}
-.mutli-selector-parents {
- color: cyan;
-}
-.foo .bar {
- width: 100%;
-}
-.underParents {
- color: red;
-}
-.parent .underParents {
- color: red;
-}
-* + h1 {
- margin-top: 25px;
-}
-legend + h1 {
- margin-top: 0;
-}
-h1 + * {
- margin-top: 10px;
-}
-* + h2 {
- margin-top: 20px;
-}
-legend + h2 {
- margin-top: 0;
-}
-h2 + * {
- margin-top: 8px;
-}
-* + h3 {
- margin-top: 15px;
-}
-legend + h3 {
- margin-top: 0;
-}
-h3 + * {
- margin-top: 5px;
-}
-.error {
- background-image: "/a.png";
- background-position: center center;
-}
-.test-rec .recursion {
- color: black;
-}
-.button {
- padding-left: 44px;
-}
-.button.large {
- padding-left: 40em;
-}
+++ /dev/null
-#operations {
- color: #111111;
- height: 9px;
- width: 3em;
- substraction: 0;
- division: 1;
-}
-#operations .spacing {
- height: 9px;
- width: 3em;
-}
-.with-variables {
- height: 16em;
- width: 24em;
- size: 1cm;
-}
-.with-functions {
- color: #646464;
- color: #ff8080;
- color: #c94a4a;
-}
-.negative {
- height: 0px;
- width: 4px;
-}
-.shorthands {
- padding: -1px 2px 0 -4px;
-}
-.rem-dimensions {
- font-size: 5.5rem;
-}
-.colors {
- color: #123;
- border-color: #334455;
- background-color: #000000;
-}
-.colors .other {
- color: #222222;
- border-color: #222222;
-}
-.negations {
- variable: -4px;
- variable1: 0px;
- variable2: 0px;
- variable3: 8px;
- variable4: 0px;
- paren: -4px;
- paren2: 16px;
-}
+++ /dev/null
-.parens {
- border: 2px solid #000000;
- margin: 1px 3px 16 3;
- width: 36;
- padding: 2px 36px;
-}
-.more-parens {
- padding: 8 4 4 4px;
- width-all: 96;
- width-first: 16 * 6;
- width-keep: (4 * 4) * 6;
- height-keep: (7 * 7) + (8 * 8);
- height-all: 113;
- height-parts: 49 + 64;
- margin-keep: (4 * (5 + 5) / 2) - (4 * 2);
- margin-parts: 20 - 8;
- margin-all: 12;
- border-radius-keep: 4px * (1 + 1) / 4 + 3px;
- border-radius-parts: 8px / 7px;
- border-radius-all: 5px;
-}
-.negative {
- neg-var: -1;
- neg-var-paren: -(1);
-}
-.nested-parens {
- width: 2 * (4 * (2 + (1 + 6))) - 1;
- height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1;
-}
-.mixed-units {
- margin: 2px 4em 1 5pc;
- padding: 6px 1em 2px 2;
-}
+++ /dev/null
-#first > .one {
- font-size: 2em;
-}
-#first > .one > #second .two > #deux {
- width: 50%;
-}
-#first > .one > #second .two > #deux #third {
- height: 100%;
-}
-#first > .one > #second .two > #deux #third:focus {
- color: black;
-}
-#first > .one > #second .two > #deux #third:focus #fifth > #sixth .seventh #eighth + #ninth {
- color: purple;
-}
-#first > .one > #second .two > #deux #fourth,
-#first > .one > #second .two > #deux #five,
-#first > .one > #second .two > #deux #six {
- color: #110000;
-}
-#first > .one > #second .two > #deux #fourth .seven,
-#first > .one > #second .two > #deux #five .seven,
-#first > .one > #second .two > #deux #six .seven,
-#first > .one > #second .two > #deux #fourth .eight > #nine,
-#first > .one > #second .two > #deux #five .eight > #nine,
-#first > .one > #second .two > #deux #six .eight > #nine {
- border: 1px solid black;
-}
-#first > .one > #second .two > #deux #fourth #ten,
-#first > .one > #second .two > #deux #five #ten,
-#first > .one > #second .two > #deux #six #ten {
- color: red;
-}
+++ /dev/null
-.tiny-scope {
- color: #998899;
-}
-.scope1 {
- color: #0000ff;
- border-color: #000000;
-}
-.scope1 .scope2 {
- color: #0000ff;
-}
-.scope1 .scope2 .scope3 {
- color: #ff0000;
- border-color: #000000;
- background-color: #ffffff;
-}
-.scope {
- scoped-val: #008000;
-}
-.heightIsSet {
- height: 1024px;
-}
-.useHeightInMixinCall {
- mixin-height: 1024px;
-}
-.imported {
- exists: true;
-}
-.testImported {
- exists: true;
-}
-#allAreUsedHere {
- default: 'top level';
- scope: 'top level';
- sub-scope-only: 'inside';
-}
+++ /dev/null
-h1 a:hover,
-h2 a:hover,
-h3 a:hover,
-h1 p:hover,
-h2 p:hover,
-h3 p:hover {
- color: red;
-}
-#all {
- color: blue;
-}
-#the {
- color: blue;
-}
-#same {
- color: blue;
-}
-ul,
-li,
-div,
-q,
-blockquote,
-textarea {
- margin: 0;
-}
-td {
- margin: 0;
- padding: 0;
-}
-td,
-input {
- line-height: 1em;
-}
-a {
- color: red;
-}
-a:hover {
- color: blue;
-}
-div a {
- color: green;
-}
-p a span {
- color: yellow;
-}
-.foo .bar .qux,
-.foo .baz .qux {
- display: block;
-}
-.qux .foo .bar,
-.qux .foo .baz {
- display: inline;
-}
-.qux.foo .bar,
-.qux.foo .baz {
- display: inline-block;
-}
-.qux .foo .bar .biz,
-.qux .foo .baz .biz {
- display: none;
-}
-.a.b.c {
- color: red;
-}
-.c .b.a {
- color: red;
-}
-.foo .p.bar {
- color: red;
-}
-.foo.p.bar {
- color: red;
-}
-.foo + .foo {
- background: amber;
-}
-.foo + .foo {
- background: amber;
-}
-.foo + .foo,
-.foo + .bar,
-.bar + .foo,
-.bar + .bar {
- background: amber;
-}
-.foo a > .foo a,
-.foo a > .bar a,
-.foo a > .foo b,
-.foo a > .bar b,
-.bar a > .foo a,
-.bar a > .bar a,
-.bar a > .foo b,
-.bar a > .bar b,
-.foo b > .foo a,
-.foo b > .bar a,
-.foo b > .foo b,
-.foo b > .bar b,
-.bar b > .foo a,
-.bar b > .bar a,
-.bar b > .foo b,
-.bar b > .bar b {
- background: amber;
-}
-.other ::fnord {
- color: #ff0000;
-}
-.other::fnord {
- color: #ff0000;
-}
-.other ::bnord {
- color: #ff0000;
-}
-.other::bnord {
- color: #ff0000;
-}
-.blood {
- color: red;
-}
-.bloodred {
- color: green;
-}
-#blood.blood.red.black {
- color: black;
-}
-:nth-child(3) {
- selector: interpolated;
-}
-.test:nth-child(odd):not(:nth-child(3)) {
- color: #ff0000;
-}
-[prop],
-[prop=10%],
-[prop="value3"],
-[prop*="val3"],
-[|prop~="val3"],
-[*|prop$="val3"],
-[ns|prop^="val3"],
-[3^="val3"],
-[3=3],
-[3] {
- attributes: yes;
-}
+++ /dev/null
-@import "css/background.css";
-/*@import "folder (1)/import-test-d.css";*/
-/*@font-face {
- src: local(Futura-Medium), url(folder\ \(1\)/fonts.svg#MyGeometricModern) format("svg");
-}*/
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-/*#misc {
- background-image: url(folder\ \(1\)/images/image.jpg);
-}*/
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-/*.comma-delimited {
- background: url(folder\ \(1\)/bg.jpg) no-repeat, url(folder\ \(1\)/bg.png) repeat-x top left, url(folder\ \(1\)/bg);
-}
-.values {
- url: url('folder (1)/Trebuchet');
-}*/
-#logo {
- width: 100px;
- height: 100px;
- background: url('assets/logo.png');
-}
-@font-face {
- font-family: xecret;
- src: url('assets/xecret.ttf');
-}
-#secret {
- font-family: xecret, sans-serif;
-}
+++ /dev/null
-#strings {
- background-image: url("http://son-of-a-banana.com");
- quotes: "~" "~";
- content: "#*%:&^,)!.(~*})";
- empty: "";
- brackets: "{" "}";
- escapes: "\"hello\" \\world";
- escapes2: "\"llo";
-}
-#comments {
- content: "/* hello */ // not-so-secret";
-}
-#single-quote {
- quotes: "'" "'";
- content: '""#!&""';
- empty: '';
- semi-colon: ';';
-}
-#escaped {
- filter: DX.Transform.MS.BS.filter(opacity=50);
-}
-#one-line {
- image: url(http://tooks.com);
-}
-#crazy {
- image: url(http://), "}", url("http://}");
-}
-#interpolation {
- url: "http://lesscss.org/dev/image.jpg";
- url2: "http://lesscss.org/image-256.jpg";
- url3: "http://lesscss.org#445566";
- url4: "http://lesscss.org/hello";
- url5: "http://lesscss.org/54.4px";
-}
-.mix-mul-class {
- color: #0000ff;
- color: #ff0000;
- color: #000000;
- color: #ffa500;
-}
-.watermark {
- family: Univers, Arial, Verdana, San-Serif;
-}
+++ /dev/null
-@import "css/background.css";
-@import "import/import-test-d.css";
-@import "file.css";
-@font-face {
- src: local(Futura-Medium), url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
- background: url("img.jpg") center / 100px;
- background: #ffffff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
- background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700");
-}
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- url: url('Trebuchet');
-}
-#logo {
- width: 100px;
- height: 100px;
- background: url('import/assets/logo.png');
-}
-@font-face {
- font-family: xecret;
- src: url('import/assets/xecret.ttf');
-}
-#secret {
- font-family: xecret, sans-serif;
-}
-#data-uri {
- uri: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==');
-}
-#data-uri-guess {
- uri: url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==');
-}
-#data-uri-ascii {
- uri-1: url('data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A');
- uri-2: url('data:text/html,%3Ch1%3EThis%20page%20is%20100%25%20Awesome.%3C%2Fh1%3E%0A');
-}
-#data-uri-toobig {
- uri: url('../data/data-uri-fail.png');
-}
-#svg-functions {
- background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjwvbGluZWFyR3JhZGllbnQ+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkaWVudCkiIC8+PC9zdmc+');
- background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwMDAwMCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg==');
- background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZ3JhZGllbnQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMCUiIHkxPSIwJSIgeDI9IjAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIxJSIgc3RvcC1jb2xvcj0iI2M0YzRjNCIvPjxzdG9wIG9mZnNldD0iMyUiIHN0b3AtY29sb3I9IiNmZmE1MDAiLz48c3RvcCBvZmZzZXQ9IjUlIiBzdG9wLWNvbG9yPSIjMDA4MDAwIi8+PHN0b3Agb2Zmc2V0PSI5NSUiIHN0b3AtY29sb3I9IiNmZmZmZmYiLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZ3JhZGllbnQpIiAvPjwvc3ZnPg==');
-}
+++ /dev/null
-.variables {
- width: 14cm;
-}
-.variables {
- height: 24px;
- color: #888888;
- font-family: "Trebuchet MS", Verdana, sans-serif;
- quotes: "~" "~";
-}
-.redef {
- zero: 0;
-}
-.redef .inition {
- three: 3;
-}
-.values {
- minus-one: -1;
- font-family: 'Trebuchet', 'Trebuchet', 'Trebuchet';
- color: #888888 !important;
- multi: something 'A', B, C, 'Trebuchet';
-}
-.variable-names {
- name: 'hello';
-}
-.alpha {
- filter: alpha(opacity=42);
-}
-.testPollution {
- a: 'no-pollution';
-}
-.units {
- width: 1px;
- same-unit-as-previously: 1px;
- square-pixel-divided: 1px;
- odd-unit: 2;
- percentage: 500%;
- pixels: 500px;
- conversion-metric-a: 30mm;
- conversion-metric-b: 3cm;
- conversion-imperial: 3in;
- custom-unit: 420octocats;
- custom-unit-cancelling: 18dogs;
- mix-units: 2px;
- invalid-units: 1px;
-}
+++ /dev/null
-.whitespace {
- color: white;
-}
-.whitespace {
- color: white;
-}
-.whitespace {
- color: white;
-}
-.whitespace {
- color: white;
-}
-.whitespace {
- color: white ;
-}
-.white,
-.space,
-.mania {
- color: white;
-}
-.no-semi-column {
- color: #ffffff;
-}
-.no-semi-column {
- color: white;
- white-space: pre;
-}
-.no-semi-column {
- border: 2px solid #ffffff;
-}
-.newlines {
- background: the,
- great,
- wall;
- border: 2px
- solid
- black;
-}
-.sel .newline_ws .tab_ws {
- color: white;
- background-position: 45 -23;
-}
+++ /dev/null
-not actually a jpeg file
+++ /dev/null
-<h1>This page is 100% Awesome.</h1>
+++ /dev/null
-/*jshint latedef: nofunc */
-var path = require('path'),
- fs = require('fs'),
- sys = require('util');
-
-var less = require('../lib/less');
-var stylize = require('../lib/less/lessc_helper').stylize;
-
-var globals = Object.keys(global);
-
-var oneTestOnly = process.argv[2];
-
-var isVerbose = process.env.npm_config_loglevel === 'verbose';
-
-var totalTests = 0,
- failedTests = 0,
- passedTests = 0;
-
-less.tree.functions.add = function (a, b) {
- return new(less.tree.Dimension)(a.value + b.value);
-};
-less.tree.functions.increment = function (a) {
- return new(less.tree.Dimension)(a.value + 1);
-};
-less.tree.functions._color = function (str) {
- if (str.value === "evil red") { return new(less.tree.Color)("600"); }
-};
-
-console.log("\n" + stylize("LESS", 'underline') + "\n");
-
-runTestSet({strictMath: true, relativeUrls: true, silent: true});
-runTestSet({strictMath: true, strictUnits: true}, "errors/",
- testErrors, null, getErrorPathReplacementFunction("errors"));
-runTestSet({strictMath: true, strictUnits: true, javascriptEnabled: false}, "no-js-errors/",
- testErrors, null, getErrorPathReplacementFunction("no-js-errors"));
-runTestSet({strictMath: true, dumpLineNumbers: 'comments'}, "debug/", null,
- function(name) { return name + '-comments'; });
-runTestSet({strictMath: true, dumpLineNumbers: 'mediaquery'}, "debug/", null,
- function(name) { return name + '-mediaquery'; });
-runTestSet({strictMath: true, dumpLineNumbers: 'all'}, "debug/", null,
- function(name) { return name + '-all'; });
-runTestSet({strictMath: true, relativeUrls: false, rootpath: "folder (1)/"}, "static-urls/");
-runTestSet({strictMath: true, compress: true}, "compression/");
-runTestSet({}, "legacy/");
-runTestSet({strictMath: true, strictUnits: true, sourceMap: true }, "sourcemaps/",
- testSourcemap, null, null, function(filename) { return path.join('test/sourcemaps', filename) + '.json'; });
-
-testNoOptions();
-
-function getErrorPathReplacementFunction(dir) {
- return function(input) {
- return input.replace(
- "{path}", path.join(process.cwd(), "/test/less/" + dir + "/"))
- .replace("{pathrel}", path.join("test", "less", dir + "/"))
- .replace("{pathhref}", "")
- .replace("{404status}", "")
- .replace(/\r\n/g, '\n');
- };
-}
-
-function testSourcemap(name, err, compiledLess, doReplacements, sourcemap) {
- fs.readFile(path.join('test/', name) + '.json', 'utf8', function (e, expectedSourcemap) {
- sys.print("- " + name + ": ");
- if (sourcemap === expectedSourcemap) {
- ok('OK');
- } else if (err) {
- fail("ERROR: " + (err && err.message));
- if (isVerbose) {
- console.error();
- console.error(err.stack);
- }
- } else {
- difference("FAIL", expectedSourcemap, sourcemap);
- }
- });
-}
-
-function testErrors(name, err, compiledLess, doReplacements) {
- fs.readFile(path.join('test/less/', name) + '.txt', 'utf8', function (e, expectedErr) {
- sys.print("- " + name + ": ");
- expectedErr = doReplacements(expectedErr, 'test/less/errors/');
- if (!err) {
- if (compiledLess) {
- fail("No Error", 'red');
- } else {
- fail("No Error, No Output");
- }
- } else {
- var errMessage = less.formatError(err);
- if (errMessage === expectedErr) {
- ok('OK');
- } else {
- difference("FAIL", expectedErr, errMessage);
- }
- }
- });
-}
-
-function globalReplacements(input, directory) {
- var p = path.join(process.cwd(), directory),
- pathimport = path.join(process.cwd(), directory + "import/"),
- pathesc = p.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); }),
- pathimportesc = pathimport.replace(/[.:/\\]/g, function(a) { return '\\' + (a=='\\' ? '\/' : a); });
-
- return input.replace(/\{path\}/g, p)
- .replace(/\{pathesc\}/g, pathesc)
- .replace(/\{pathimport\}/g, pathimport)
- .replace(/\{pathimportesc\}/g, pathimportesc)
- .replace(/\r\n/g, '\n');
-}
-
-function checkGlobalLeaks() {
- return Object.keys(global).filter(function(v) {
- return globals.indexOf(v) < 0;
- });
-}
-
-function runTestSet(options, foldername, verifyFunction, nameModifier, doReplacements, getFilename) {
- foldername = foldername || "";
-
- if(!doReplacements) {
- doReplacements = globalReplacements;
- }
-
- fs.readdirSync(path.join('test/less/', foldername)).forEach(function (file) {
- if (! /\.less/.test(file)) { return; }
-
- var name = foldername + path.basename(file, '.less');
-
- if (oneTestOnly && name !== oneTestOnly) {
- return;
- }
-
- totalTests++;
-
- if (options.sourceMap) {
- var sourceMapOutput;
- options.writeSourceMap = function(output) {
- sourceMapOutput = output;
- };
- options.sourceMapOutputFilename = name + ".css";
- options.sourceMapBasepath = path.join(process.cwd(), "test/less");
- options.sourceMapRootpath = "testweb/";
- }
-
- toCSS(options, path.join('test/less/', foldername + file), function (err, less) {
-
- if (verifyFunction) {
- return verifyFunction(name, err, less, doReplacements, sourceMapOutput);
- }
- var css_name = name;
- if(nameModifier) { css_name = nameModifier(name); }
- fs.readFile(path.join('test/css', css_name) + '.css', 'utf8', function (e, css) {
- sys.print("- " + css_name + ": ");
-
- css = css && doReplacements(css, 'test/less/' + foldername);
- if (less === css) { ok('OK'); }
- else if (err) {
- fail("ERROR: " + (err && err.message));
- if (isVerbose) {
- console.error();
- console.error(err.stack);
- }
- } else {
- difference("FAIL", css, less);
- }
- });
- });
- });
-}
-
-function diff(left, right) {
- require('diff').diffLines(left, right).forEach(function(item) {
- if(item.added || item.removed) {
- var text = item.value.replace("\n", String.fromCharCode(182) + "\n");
- sys.print(stylize(text, item.added ? 'green' : 'red'));
- } else {
- sys.print(item.value);
- }
- });
- console.log("");
-}
-
-function fail(msg) {
- console.error(stylize(msg, 'red'));
- failedTests++;
- endTest();
-}
-
-function difference(msg, left, right) {
- console.warn(stylize(msg, 'yellow'));
- failedTests++;
-
- diff(left, right);
- endTest();
-}
-
-function ok(msg) {
- console.log(stylize(msg, 'green'));
- passedTests++;
- endTest();
-}
-
-function endTest() {
- var leaked = checkGlobalLeaks();
- if (failedTests + passedTests === totalTests) {
- console.log("");
- if (failedTests > 0) {
- console.error(failedTests + stylize(" Failed", "red") + ", " + passedTests + " passed");
- } else {
- console.log(stylize("All Passed ", "green") + passedTests + " run");
- }
- if (leaked.length > 0) {
- console.log("");
- console.warn(stylize("Global leak detected: ", "red") + leaked.join(', '));
- }
-
- if (leaked.length || failedTests) {
- //process.exit(1);
- process.on('exit', function() { process.reallyExit(1) });
- }
- }
-}
-
-function toCSS(options, path, callback) {
- var css;
- options = options || {};
- fs.readFile(path, 'utf8', function (e, str) {
- if (e) { return callback(e); }
-
- options.paths = [require('path').dirname(path)];
- options.filename = require('path').resolve(process.cwd(), path);
- options.optimization = options.optimization || 0;
-
- new(less.Parser)(options).parse(str, function (err, tree) {
- if (err) {
- callback(err);
- } else {
- try {
- css = tree.toCSS(options);
- callback(null, css);
- } catch (e) {
- callback(e);
- }
- }
- });
- });
-}
-
-function testNoOptions() {
- totalTests++;
- try {
- sys.print("- Integration - creating parser without options: ");
- new(less.Parser)();
- } catch(e) {
- fail(stylize("FAIL\n", "red"));
- return;
- }
- ok(stylize("OK\n", "green"));
-}
+++ /dev/null
-@charset "UTF-8";
-
-@import "import/import-charset-test";
\ No newline at end of file
+++ /dev/null
-#yelow {
- #short {
- color: #fea;
- }
- #long {
- color: #ffeeaa;
- }
- #rgba {
- color: rgba(255, 238, 170, 0.1);
- }
- #argb {
- color: argb(rgba(255, 238, 170, 0.1));
- }
-}
-
-#blue {
- #short {
- color: #00f;
- }
- #long {
- color: #0000ff;
- }
- #rgba {
- color: rgba(0, 0, 255, 0.1);
- }
- #argb {
- color: argb(rgba(0, 0, 255, 0.1));
- }
-}
-
-#alpha #hsla {
- color: hsla(11, 20%, 20%, 0.6);
-}
-
-#overflow {
- .a { color: (#111111 - #444444); } // #000000
- .b { color: (#eee + #fff); } // #ffffff
- .c { color: (#aaa * 3); } // #ffffff
- .d { color: (#00ee00 + #009900); } // #00ff00
-}
-
-#grey {
- color: rgb(200, 200, 200);
-}
-
-#333333 {
- color: rgb(20%, 20%, 20%);
-}
-
-#808080 {
- color: hsl(50, 0%, 50%);
-}
-
-#00ff00 {
- color: hsl(120, 100%, 50%);
-}
-
-.lightenblue {
- color: lighten(blue, 10%);
-}
-
-.darkenblue {
- color: darken(blue, 10%);
-}
-
-.unknowncolors {
- color: blue2;
- border: 2px solid superred;
-}
-
-.transparent {
- color: transparent;
- background-color: rgba(0, 0, 0, 0);
-}
-#alpha {
- @colorvar: rgba(150, 200, 150, 0.7);
- #fromvar {
- opacity: alpha(@colorvar);
- }
- #short {
- opacity: alpha(#aaa);
- }
- #long {
- opacity: alpha(#bababa);
- }
- #rgba {
- opacity: alpha(rgba(50, 120, 95, 0.2));
- }
- #hsl {
- opacity: alpha(hsl(120, 100%, 50%));
- }
-}
+++ /dev/null
-/******************\
-* *
-* Comment Header *
-* *
-\******************/
-
-/*
-
- Comment
-
-*/
-
-/*
- * Comment Test
- *
- * - cloudhead (http://cloudhead.net)
- *
- */
-
-////////////////
-@var: "content";
-////////////////
-
-/* Colors
- * ------
- * #EDF8FC (background blue)
- * #166C89 (darkest blue)
- *
- * Text:
- * #333 (standard text) // A comment within a comment!
- * #1F9EC9 (standard link)
- *
- */
-
-/* @group Variables
-------------------- */
-#comments /* boo *//* boo again*/,
-//.commented_out1
-//.commented_out2
-//.commented_out3
-.comments //end of comments1
-//end of comments2
-{
- /**/ // An empty comment
- color: red; /* A C-style comment */ /* A C-style comment */
- background-color: orange; // A little comment
- font-size: 12px;
-
- /* lost comment */ content: @var;
-
- border: 1px solid black;
-
- // padding & margin //
- padding: 0; // }{ '"
- margin: 2em;
-} //
-
-/* commented out
- #more-comments {
- color: grey;
- }
-*/
-
-.selector /* .with */, .lots, /* of */ .comments {
- color: grey, /* blue */ orange;
- -webkit-border-radius: 2px /* webkit only */;
- -moz-border-radius: (2px * 4) /* moz only with operation */;
-}
-
-.mixin_def_with_colors(@a: white, // in
- @b: 1px //put in @b - causes problems! --->
- ) // the
- when (@a = white) {
- .test {
- color: @b;
- }
-}
-.mixin_def_with_colors();
-
-#last { color: blue }
-//
-
-/* *//* { *//* *//* *//* */#div { color:#A33; }/* } */
+++ /dev/null
-#colours {
- color1: #fea;
- color2: #ffeeaa;
- color3: rgba(255, 238, 170, 0.1);
- @color1: #fea;
- string: "@{color1}";
- /* comments are stripped */
- // both types!
- /*! but not this type
- Note preserved whitespace
- */
-}
-dimensions {
- val: 0.1px;
- val: 0em;
- val: 4cm;
- val: 0.2;
- val: 5;
- angles-must-have-unit: 0deg;
- durations-must-have-unit: 0s;
- length-doesnt-have-unit: 0px;
- width: auto\9;
-}
-@page {
- marks: none;
-@top-left-corner {
- vertical-align: top;
-}
-@top-left {
- vertical-align: top;
-}
-}
\ No newline at end of file
+++ /dev/null
-.comma-delimited {
- text-shadow: -1px -1px 1px red, 6px 5px 5px yellow;
- -moz-box-shadow: 0pt 0pt 2px rgba(255, 255, 255, 0.4) inset,
- 0pt 4px 6px rgba(255, 255, 255, 0.4) inset;
- -webkit-transform: rotate(-0.0000000001deg);
-}
-@font-face {
- font-family: Headline;
- unicode-range: U+??????, U+0???, U+0-7F, U+A5;
-}
-.other {
- -moz-transform: translate(0, 11em) rotate(-90deg);
- transform: rotateX(45deg);
-}
-.item[data-cra_zy-attr1b-ut3=bold] {
- font-weight: bold;
-}
-p:not([class*="lead"]) {
- color: black;
-}
-
-input[type="text"].class#id[attr=32]:not(1) {
- color: white;
-}
-
-div#id.class[a=1][b=2].class:not(1) {
- color: white;
-}
-
-ul.comma > li:not(:only-child)::after {
- color: white;
-}
-
-ol.comma > li:nth-last-child(2)::after {
- color: white;
-}
-
-li:nth-child(4n+1),
-li:nth-child(-5n),
-li:nth-child(-n+2) {
- color: white;
-}
-
-a[href^="http://"] {
- color: black;
-}
-
-a[href$="http://"] {
- color: black;
-}
-
-form[data-disabled] {
- color: black;
-}
-
-p::before {
- color: black;
-}
-
-#issue322 {
- -webkit-animation: anim2 7s infinite ease-in-out;
-}
-
-@-webkit-keyframes frames {
- 0% { border: 1px }
- 5.5% { border: 2px }
- 100% { border: 3px }
-}
-
-@keyframes fontbulger1 {
- to {
- font-size: 15px;
- }
- from,to {
- font-size: 12px;
- }
- 0%,100% {
- font-size: 12px;
- }
-}
-
-.units {
- font: 1.2rem/2rem;
- font: 8vw/9vw;
- font: 10vh/12vh;
- font: 12vm/15vm;
- font: 12vmin/15vmin;
- font: 1.2ch/1.5ch;
-}
-
-@supports ( box-shadow: 2px 2px 2px black ) or
- ( -moz-box-shadow: 2px 2px 2px black ) {
- .outline {
- box-shadow: 2px 2px 2px black;
- -moz-box-shadow: 2px 2px 2px black;
- }
-}
-
-@-x-document url-prefix(""github.com"") {
- h1 {
- color: red;
- }
-}
-
-@viewport {
- font-size: 10px;
-}
-@namespace foo url(http://www.example.com);
-
-foo|h1 { color: blue; }
-foo|* { color: yellow; }
-|h1 { color: red; }
-*|h1 { color: green; }
-h1 { color: green; }
-.upper-test {
- UpperCaseProperties: allowed;
-}
-@host {
- div {
- display: block;
- }
-}
-::distributed(input::placeholder) {
- color: #b3b3b3;
-}
\ No newline at end of file
+++ /dev/null
-@ugly: fuchsia;
-
-.escape\|random\|char {
- color: red;
-}
-
-.mixin\!tUp {
- font-weight: bold;
-}
-
-// class="404"
-.\34 04 {
- background: red;
-
- strong {
- color: @ugly;
- .mixin\!tUp;
- }
-}
-
-.trailingTest\+ {
- color: red;
-}
-
-/* This hideous test of hideousness checks for the selector "blockquote" with various permutations of hex escapes */
-\62\6c\6f \63 \6B \0071 \000075o\74 e {
- color: silver;
-}
-
-[ng\:cloak],
-ng\:form {
- display: none;
-}
+++ /dev/null
-
-.light when (lightness(@a) > 50%) {
- color: green;
-}
-.dark when (lightness(@a) < 50%) {
- color: orange;
-}
-@a: #ddd;
-
-.see-the {
- @a: #444; // this mirrors what mixins do - they evaluate guards at the point of execution
- .light();
- .dark();
-}
-
-.hide-the {
- .light();
- .dark();
-}
-
-.multiple-conditions-1 when (@b = 1), (@c = 2), (@d = 3) {
- color: red;
-}
-
-.multiple-conditions-2 when (@b = 1), (@c = 2), (@d = 2) {
- color: blue;
-}
-
-@b: 2;
-@c: 3;
-@d: 3;
-
-.inheritance when (@b = 2) {
- .test {
- color: black;
- }
- &:hover {
- color: pink;
- }
- .hideme when (@b = 1) {
- color: green;
- }
- & when (@b = 1) {
- hideme: green;
- }
-}
-
-.hideme when (@b = 1) {
- .test {
- color: black;
- }
- &:hover {
- color: pink;
- }
- .hideme when (@b = 1) {
- color: green;
- }
-}
-
-& when (@b = 1) {
- .hideme {
- color: red;
- }
-}
\ No newline at end of file
+++ /dev/null
-@charset "utf-8";
-div { color: black; }
-div { width: 99%; }
-
-* {
- min-width: 45em;
-}
-
-h1, h2 > a > p, h3 {
- color: unset;
-}
-
-div.class {
- color: blue;
-}
-
-div#id {
- color: green;
-}
-
-.class#id {
- color: purple;
-}
-
-.one.two.three {
- color: grey;
-}
-
-@media print {
- * {
- font-size: 3em;
- }
-}
-
-@media screen {
- * {
- font-size: 10px;
- }
-}
-
-@font-face {
- font-family: 'Garamond Pro';
-}
-
-a:hover, a:link {
- color: #999;
-}
-
-p, p:first-child {
- text-transform: none;
-}
-
-q:lang(no) {
- quotes: none;
-}
-
-p + h1 {
- font-size: +2.2em;
-}
-
-#shorthands {
- border: 1px solid #000;
- font: 12px/16px Arial;
- font: 100%/16px Arial;
- margin: 1px 0;
- padding: 0 auto;
-}
-
-#more-shorthands {
- margin: 0.1%;
- padding: 1px 0 2px 0;
- font: normal small/20px 'Trebuchet MS', Verdana, sans-serif;
- font: 0/0 a;
- border-radius: 5px / 10px;
-}
-
-.misc {
- -moz-border-radius: 2px;
- display: -moz-inline-stack;
- width: .1em;
- background-color: #009998;
- background: -webkit-gradient(linear, left top, left bottom, from(red), to(blue));
- .nested-multiple {
- multiple-semi-colons: yes;;;;;;
- };
- filter: alpha(opacity=100);
- width: auto\9;
-}
-
-#important {
- color: red !important;
- width: 100%!important;
- height: 20px ! important;
-}
-
-.def-font(@name) {
- @font-face {
- font-family: @name
- }
-}
-
-.def-font(font-a);
-.def-font(font-b);
-
-.æøå {
- margin: 0;
-}
+++ /dev/null
-@charset "ISO-8859-1";
-
-.mixin_import1() {
- @media all {
- .tst {
- color: black;
- @media screen {
- color: red;
- .tst3 {
- color: white;
- }
- }
- }
- }
-}
-
-.mixin_import2() {
- .tst2 {
- color: white;
- }
-}
-
-.tst3 {
- color: grey;
-}
\ No newline at end of file
+++ /dev/null
-@charset "UTF-8";
-
-@import "import/test.less";
-
-.start() {
- .test2 {
- color: red;
- }
-}
-
-.mix() {
- color: black;
-}
-
-.test1 {
- .mix();
-}
-
-.start();
-
-.mixin_import1();
-
-.mixin_import2();
\ No newline at end of file
+++ /dev/null
-.a {
- error: (1px + 3em);
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px' and 'em'. in {path}add-mixed-units.less on line null, column 0:
-1 error: (1px + 3em);
+++ /dev/null
-.a {
- error: ((1px * 2px) + (3em * 3px));
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Incompatible units. Change the units or use the unit function. Bad units: 'px*px' and 'em*px'. in {path}add-mixed-units2.less on line null, column 0:
-1 error: ((1px * 2px) + (3em * 3px));
+++ /dev/null
-@@demo: "hi";
\ No newline at end of file
+++ /dev/null
-ParseError: Unrecognised input in {path}bad-variable-declaration1.less on line 1, column 1:
-1 @@demo: "hi";
+++ /dev/null
-.test {
- color: color("NOT A COLOR");
-}
\ No newline at end of file
+++ /dev/null
-ArgumentError: error evaluating function `color`: argument must be a color keyword or 3/6 digit hex e.g. #FFF in {path}color-func-invalid-color.less on line 2, column 10:
-1 .test {
-2 color: color("NOT A COLOR");
-3 }
+++ /dev/null
-.a {
- prop: (3 / #fff);
-}
\ No newline at end of file
+++ /dev/null
-OperationError: Can't substract or divide a color from a number in {path}color-operation-error.less on line null, column 0:
-1 prop: (3 / #fff);
+++ /dev/null
-#gaga /* Comment */ span { color: red }
\ No newline at end of file
+++ /dev/null
-ParseError: Unrecognised input in {path}comment-in-selector.less on line 1, column 21:
-1 #gaga /* Comment */ span { color: red }
+++ /dev/null
-.a {
- error: (1px / 3em);
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: px/em in {path}divide-mixed-units.less on line 2, column 3:
-1 .a {
-2 error: (1px / 3em);
-3 }
+++ /dev/null
-:extend(.a all) {
- property: red;
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Extend must be used to extend a selector, it cannot be used on its own in {path}extend-no-selector.less on line 1, column 17:
-1 :extend(.a all) {
-2 property: red;
+++ /dev/null
-.a:extend(.b all).c {
- property: red;
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Extend can only be used at the end of selector in {path}extend-not-at-end.less on line 1, column 21:
-1 .a:extend(.b all).c {
-2 property: red;
+++ /dev/null
-.a {
- color: green;
- // tests line number for import reference is correct
-}
-
-@import "file-does-not-exist.less";
\ No newline at end of file
+++ /dev/null
-FileError: '{pathhref}file-does-not-exist.less' wasn't found{404status} in {path}import-missing.less on line 6, column 1:
-5
-6 @import "file-does-not-exist.less";
+++ /dev/null
-@import "this-statement-is-invalid.less"
\ No newline at end of file
+++ /dev/null
-ParseError: Unrecognised input in {path}import-no-semi.less on line 1, column 1:
-1 @import "this-statement-is-invalid.less"
+++ /dev/null
-@import "imports/import-subfolder1.less";
\ No newline at end of file
+++ /dev/null
-NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1:
-10
-11 .mixin-not-defined();
+++ /dev/null
-@import "imports/import-subfolder2.less";
\ No newline at end of file
+++ /dev/null
-ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 1, column 2:
-1 }}
+++ /dev/null
-@import "subfolder/mixin-not-defined.less";
\ No newline at end of file
+++ /dev/null
-@import "subfolder/parse-error-curly-bracket.less";
\ No newline at end of file
+++ /dev/null
-.someclass
-{
- font-weight: bold;
-}
\ No newline at end of file
+++ /dev/null
-@import "../../mixin-not-defined.less";
\ No newline at end of file
+++ /dev/null
-@import "../../parse-error-curly-bracket.less";
\ No newline at end of file
+++ /dev/null
-.scope {
- var: `this.foo.toJS()`;
-}
+++ /dev/null
-SyntaxError: JavaScript evaluation error: 'TypeError: Cannot call method 'toJS' of undefined' in {path}javascript-error.less on line 2, column 27:
-1 .scope {
-2 var: `this.foo.toJS()`;
-3 }
+++ /dev/null
-.mixin(@a : 4, @b : 3, @c: 2) {
- will: fail;
-}
-.mixin-test {
- .mixin(@a: 5; @b: 6, @c: 7);
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-1.less on line 5, column 30:
-4 .mixin-test {
-5 .mixin(@a: 5; @b: 6, @c: 7);
-6 }
+++ /dev/null
-.mixin(@a : 4, @b : 3, @c: 2) {
- will: fail;
-}
-.mixin-test {
- .mixin(@a: 5, @b: 6; @c: 7);
-}
+++ /dev/null
-SyntaxError: Cannot mix ; and , as delimiter types in {path}mixed-mixin-definition-args-2.less on line 5, column 26:
-4 .mixin-test {
-5 .mixin(@a: 5, @b: 6; @c: 7);
-6 }
+++ /dev/null
-
-.error-is-further-on() {
-}
-
-.pad-here-to-reproduce-error-in() {
-}
-
-.the-import-subfolder-test() {
-}
-
-.mixin-not-defined();
\ No newline at end of file
+++ /dev/null
-NameError: .mixin-not-defined is undefined in {path}mixin-not-defined.less on line 11, column 1:
-10
-11 .mixin-not-defined();
+++ /dev/null
-@saxofon:trumpete;
-
-.mixin(saxofon) {
-}
-
-.mixin(@saxofon);
\ No newline at end of file
+++ /dev/null
-RuntimeError: No matching definition was found for `.mixin(trumpete)` in {path}mixin-not-matched.less on line 6, column 1:
-5
-6 .mixin(@saxofon);
+++ /dev/null
-@saxofon:trumpete;
-
-.mixin(@a, @b) {
-}
-
-.mixin(@a: @saxofon);
\ No newline at end of file
+++ /dev/null
-RuntimeError: No matching definition was found for `.mixin(@a:trumpete)` in {path}mixin-not-matched2.less on line 6, column 1:
-5
-6 .mixin(@a: @saxofon);
+++ /dev/null
-@ie8: true;
-.a when (@ie8 = true),
-.b {
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Guards are only currently allowed on a single selector. in {path}multiple-guards-on-css-selectors.less on line 3, column 1:
-2 .a when (@ie8 = true),
-3 .b {
-4 }
+++ /dev/null
-/* Test */
-#blah {
- // blah
-}
-.a {
- error: (1px * 1em);
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: Multiple units in dimension. Correct the units or use the unit function. Bad unit: em*px in {path}multiply-mixed-units.less on line 6, column 3:
-5 .a {
-6 error: (1px * 1em);
-7 }
+++ /dev/null
-.a {
- something: (12 (13 + 5 -23) + 5);
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: expected ')' got '(' in {path}parens-error-1.less on line 2, column 18:
-1 .a {
-2 something: (12 (13 + 5 -23) + 5);
-3 }
+++ /dev/null
-.a {
- something: (12 * (13 + 5 -23));
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: expected ')' got '-' in {path}parens-error-2.less on line 2, column 28:
-1 .a {
-2 something: (12 * (13 + 5 -23));
-3 }
+++ /dev/null
-.a {
- something: (12 + (13 + 10 -23));
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: expected ')' got '-' in {path}parens-error-3.less on line 2, column 29:
-1 .a {
-2 something: (12 + (13 + 10 -23));
-3 }
+++ /dev/null
-}}
\ No newline at end of file
+++ /dev/null
-ParseError: missing opening `{` in {path}parse-error-curly-bracket.less on line 1, column 2:
-1 }}
+++ /dev/null
-body {
- background-color: #fff;
+++ /dev/null
-ParseError: missing closing `}` in {path}parse-error-missing-bracket.less on line 3, column 1:
-2 background-color: #fff;
-3
+++ /dev/null
-@import 'import/import-test.less';
-
-body
-{
- font-family: arial, sans-serif;
-}
-
-nonsense;
-
-.clickable
-{
- cursor: pointer;
-}
\ No newline at end of file
+++ /dev/null
-ParseError: Unrecognised input in {path}parse-error-with-import.less on line 8, column 9:
-7
-8 nonsense;
-9
+++ /dev/null
-.test {
- display/*/: block; /*sorry for IE5*/
-}
\ No newline at end of file
+++ /dev/null
-ParseError: Unrecognised input in {path}property-ie5-hack.less on line 2, column 3:
-1 .test {
-2 display/*/: block; /*sorry for IE5*/
-3 }
+++ /dev/null
-.a() {
- prop:1;
-}
-.a();
\ No newline at end of file
+++ /dev/null
-SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3:
-1 .a() {
-2 prop:1;
-3 }
+++ /dev/null
-@import "property-in-root";
\ No newline at end of file
+++ /dev/null
-SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root.less on line 2, column 3:
-1 .a() {
-2 prop:1;
-3 }
+++ /dev/null
-prop:1;
-.a {
- prop:1;
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: properties must be inside selector blocks, they cannot be in the root. in {path}property-in-root3.less on line 1, column 1:
-1 prop:1;
-2 .a {
+++ /dev/null
-@bodyColor: darken(@bodyColor, 30%);
\ No newline at end of file
+++ /dev/null
-NameError: Recursive variable definition for @bodyColor in {path}recursive-variable.less on line 1, column 20:
-1 @bodyColor: darken(@bodyColor, 30%);
+++ /dev/null
-.a {
- a: svg-gradient(horizontal, black, white);
-}
\ No newline at end of file
+++ /dev/null
-ArgumentError: error evaluating function `svg-gradient`: svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center' in {path}svg-gradient1.less on line 2, column 6:
-1 .a {
-2 a: svg-gradient(horizontal, black, white);
-3 }
+++ /dev/null
-.a {
- a: svg-gradient(to bottom, black, orange, 45%, white);
-}
\ No newline at end of file
+++ /dev/null
-ArgumentError: error evaluating function `svg-gradient`: svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] in {path}svg-gradient2.less on line 2, column 6:
-1 .a {
-2 a: svg-gradient(to bottom, black, orange, 45%, white);
-3 }
+++ /dev/null
-.a {
- a: svg-gradient(black, orange);
-}
\ No newline at end of file
+++ /dev/null
-ArgumentError: error evaluating function `svg-gradient`: svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position] in {path}svg-gradient3.less on line 2, column 6:
-1 .a {
-2 a: svg-gradient(black, orange);
-3 }
+++ /dev/null
-.a {
- font-size: unit(80/16,rem);
-}
\ No newline at end of file
+++ /dev/null
-ArgumentError: error evaluating function `unit`: the first argument to unit must be a number. Have you forgotten parenthesis? in {path}unit-function.less on line 2, column 14:
-1 .a {
-2 font-size: unit(80/16,rem);
-3 }
+++ /dev/null
-//very simple chaining
-.a {
- color: black;
-}
-.b:extend(.a) {}
-.c:extend(.b) {}
-
-//very simple chaining, ordering not important
-
-.d:extend(.e) {}
-.e:extend(.f) {}
-.f {
- color: black;
-}
-
-//extend with all
-
-.g.h {
- color: black;
-}
-.i.j:extend(.g all) {
- color: white;
-}
-.k:extend(.i all) {}
-
-//extend multi-chaining
-
-.l {
- color: black;
-}
-.m:extend(.l){}
-.n:extend(.m){}
-.o:extend(.n){}
-.p:extend(.o){}
-.q:extend(.p){}
-.r:extend(.q){}
-.s:extend(.r){}
-.t:extend(.s){}
-
-// self referencing is ignored
-
-.u {color: black;}
-.v.u.v:extend(.u all){}
-
-// circular reference because the new extend product will match the existing extend
-
-.w:extend(.w) {color: black;}
-.v.w.v:extend(.w all){}
-
-// classic circular references
-
-.x:extend(.z) {
- color: x;
-}
-.y:extend(.x) {
- color: y;
-}
-.z:extend(.y) {
- color: z;
-}
-
-//very simple chaining, but with the extend inside the ruleset
-.va {
- color: black;
-}
-.vb {
- &:extend(.va);
- color: white;
-}
-.vc {
- &:extend(.vb);
-}
-
-// media queries - dont extend outside, do extend inside
-
-@media tv {
- .ma:extend(.a,.b,.c,.d,.e,.f,.g,.h,.i,.j,.k,.l,.m,.n,.o,.p,.q,.r,.s,.t,.u,.v,.w,.x,.y,.z,.md) {
- color: black;
- }
- .md {
- color: white;
- }
- @media plasma {
- .me, .mf {
- &:extend(.mb,.md);
- background: red;
- }
- }
-}
-.mb:extend(.ma) {};
-.mc:extend(.mb) {};
\ No newline at end of file
+++ /dev/null
-.clearfix {
- *zoom: 1;
- &:after {
- content: '';
- display: block;
- clear: both;
- height: 0;
- }
-}
-
-.foo {
- &:extend(.clearfix all);
- color: red;
-}
-
-.bar {
- &:extend(.clearfix all);
- color: blue;
-}
+++ /dev/null
-.replace.replace,
-.c.replace + .replace {
- .replace,
- .c {
- prop: copy-paste-replace;
- }
-}
-.rep_ace:extend(.replace.replace .replace) {}
-
-.a .b .c {
- prop: not_effected;
-}
-
-.a {
- prop: is_effected;
- .b {
- prop: not_effected;
- }
- .b.c {
- prop: not_effected;
- }
-}
-
-.c, .a {
- .b, .a {
- .a, .c {
- prop: not_effected;
- }
- }
-}
-
-.effected {
- &:extend(.a);
- &:extend(.b);
- &:extend(.c);
-}
-
-.e {
- && {
- prop: extend-double;
- &:hover {
- hover: not-extended;
- }
- }
-}
-.dbl:extend(.e.e) {}
+++ /dev/null
-.ext1 .ext2 {
- background: black;
-}
-
-@media tv {
- .ext1 .ext3 {
- color: white;
- }
- .tv-lowres :extend(.ext1 all) {
- background: blue;
- }
- @media hires {
- .ext1 .ext4 {
- color: green;
- }
- .tv-hires :extend(.ext1 all) {
- background: red;
- }
- }
-}
-
-.all:extend(.ext1 all) {
-
-}
\ No newline at end of file
+++ /dev/null
-.sidebar {
- width: 300px;
- background: red;
-
- .box {
- background: #FFF;
- border: 1px solid #000;
- margin: 10px 0;
- }
-}
-
-.sidebar2 {
- &:extend(.sidebar all);
- background: blue;
-}
-
-.type1 {
- .sidebar3 {
- &:extend(.sidebar all);
- background: green;
- }
-}
-
-.type2 {
- &.sidebar4 {
- &:extend(.sidebar all);
- background: red;
- }
-}
-
-.button {
- color: black;
- &:hover {
- color: white;
- }
-}
-.submit {
- &:extend(.button);
- &:hover:extend(.button:hover) {}
-}
-
-.nomatch {
- &:hover:extend(.button :hover) {}
-}
-
-.button2 {
- :hover {
- nested: white;
- }
-}
-.button2 :hover {
- notnested: black;
-}
-
-.nomatch :extend(.button2:hover) {}
-
-.amp-test-a,
-.amp-test-b {
- .amp-test-c &.amp-test-d&.amp-test-e {
- .amp-test-f&+&.amp-test-g:extend(.amp-test-h) {}
- }
-}
-.amp-test-h {
- test: extended by masses of selectors;
-}
\ No newline at end of file
+++ /dev/null
-.error {
- border: 1px #f00;
- background: #fdd;
-}
-.error.intrusion {
- font-size: 1.3em;
- font-weight: bold;
-}
-.intrusion .error {
- display: none;
-}
-.badError:extend(.error all) {
- border-width: 3px;
-}
-
-.foo .bar, .foo .baz {
- display: none;
-}
-
-.ext1 .ext2
- :extend(.foo all) {
-}
-
-.ext3:extend(.foo all),
-.ext4:extend(.foo all) {
-}
-
-div.ext5,
-.ext6 > .ext5 {
- width: 100px;
-}
-
-.should-not-exist-in-output,
-.ext7:extend(.ext5 all) {
-}
-
-.ext {
- test: 1;
-}
-// same as
-// .a .c:extend(.ext all)
-// .b .c:extend(.ext all)
-// .a .c .d
-// .b .c .d
-.a, .b {
- test: 2;
- .c:extend(.ext all) {
- test: 3;
- .d {
- test: 4;
- }
- }
-}
-
-.replace.replace,
-.c.replace + .replace {
- .replace,
- .c {
- prop: copy-paste-replace;
- }
-}
-.rep_ace:extend(.replace all) {}
-
-.attributes {
- [data="test"] {
- extend: attributes;
- }
- .attribute-test {
- &:extend([data="test"] all);
- }
- [data] {
- extend: attributes2;
- }
- .attribute-test2 {
- &:extend([data] all); //you could argue it should match [data="test"]... not for now though...
- }
- @attr-data: "test3";
- [data=@{attr-data}] {
- extend: attributes2;
- }
- .attribute-test {
- &:extend([data="test3"] all);
- }
-}
-
-.header {
- .header-nav {
- background: red;
- &:before {
- background: blue;
- }
- }
-}
-
-.footer {
- .footer-nav {
- &:extend( .header .header-nav all );
- }
-}
\ No newline at end of file
+++ /dev/null
-.error {
- border: 1px #f00;
- background: #fdd;
-}
-.error.intrusion {
- font-size: 1.3em;
- font-weight: bold;
-}
-.intrusion .error {
- display: none;
-}
-.badError {
- &:extend(.error all);
- border-width: 3px;
-}
-
-.foo .bar, .foo .baz {
- display: none;
-}
-
-.ext1 .ext2 {
- &:extend(.foo all);
-}
-
-.ext3,
-.ext4 {
- &:extend(.foo all);
- &:extend(.bar all);
-}
-
-div.ext5,
-.ext6 > .ext5 {
- width: 100px;
-}
-
-.ext7 {
- &:extend(.ext5 all);
-}
-
-.ext8.ext9 {
- result: add-foo;
-}
-.ext8 .ext9,
-.ext8 + .ext9,
-.ext8 > .ext9 {
- result: bar-matched;
-}
-.ext8.nomatch {
- result: none;
-}
-.ext8 {
- .ext9 {
- result: match-nested-bar;
- }
-}
-.ext8 {
- &.ext9 {
- result: match-nested-foo;
- }
-}
-
-.fuu:extend(.ext8.ext9 all) {}
-.buu:extend(.ext8 .ext9 all) {}
-.zap:extend(.ext8 + .ext9 all) {}
-.zoo:extend(.ext8 > .ext9 all) {}
-
-.aa {
- color: black;
- .dd {
- background: red;
- }
-}
-.bb {
- background: red;
- .bb {
- color: black;
- }
-}
-.cc:extend(.aa,.bb) {}
-.ee:extend(.dd all,.bb) {}
-.ff:extend(.dd,.bb all) {}
\ No newline at end of file
+++ /dev/null
-
-// simple array/list:
-
-.multiunit {
- @v: abc "abc" 1 1px 1% #123;
- length: length(@v);
- extract: extract(@v, 1) extract(@v, 2) extract(@v, 3) extract(@v, 4) extract(@v, 5) extract(@v, 6);
-}
-
-.incorrect-index {
- @v1: a b c;
- @v2: a, b, c;
- v1: extract(@v1, 5);
- v2: extract(@v2, -2);
-}
-
-.scalar {
- @var: variable;
- var-value: extract(@var, 1);
- var-length: length(@var);
- ill-index: extract(@var, 2);
-
- name-value: extract(name, 1);
- string-value: extract("string", 1);
- number-value: extract(12345678, 1);
- color-value: extract(blue, 1);
- rgba-value: extract(rgba(80, 160, 240, 0.67), 1);
- empty-value: extract(~'', 1);
-
- name-length: length(name);
- string-length: length("string");
- number-length: length(12345678);
- color-length: length(blue);
- rgba-length: length(rgba(80, 160, 240, 0.67));
- empty-length: length(~'');
-}
-
-.mixin-arguments {
- .mixin-args(a b c d);
- .mixin-args(a, b, c, d);
- .mixin-args(1; 2; 3; 4);
-}
-
-.mixin-args(@value) {
- &-1 {
- length: length(@value);
- extract: extract(@value, 3) ~"|" extract(@value, 2) ~"|" extract(@value, 1);
- }
-}
-
-.mixin-args(...) {
- &-2 {
- length: length(@arguments);
- extract: extract(@arguments, 3) ~"|" extract(@arguments, 2) ~"|" extract(@arguments, 1);
- }
-}
-
-.mixin-args(@values...) {
- &-3 {
- length: length(@values);
- extract: extract(@values, 3) ~"|" extract(@values, 2) ~"|" extract(@values, 1);
- }
-}
-
-.mixin-args(@head, @tail...) {
- &-4 {
- length: length(@tail);
- extract: extract(@tail, 2) ~"|" extract(@tail, 1);
- }
-}
-
-// "multidimensional" array/list
-
-.md-space-comma {
- @v: a b c, 1 2 3, "x" "y" "z";
- length-1: length(@v);
- extract-1: extract(@v, 2);
- length-2: length(extract(@v, 2));
- extract-2: extract(extract(@v, 2), 2);
-
- &-as-args {.mixin-args(a b c, 1 2 3, "x" "y" "z")}
-}
-
-.md-cat-space-comma {
- @a: a b c;
- @b: 1 2 3;
- @c: "x" "y" "z";
- @v: @a, @b, @c;
- length-1: length(@v);
- extract-1: extract(@v, 2);
- length-2: length(extract(@v, 2));
- extract-2: extract(extract(@v, 2), 2);
-
- &-as-args {.mixin-args(@a, @b, @c)}
-}
-
-.md-cat-comma-space {
- @a: a, b, c;
- @b: 1, 2, 3;
- @c: "x", "y", "z";
- @v: @a @b @c;
- length-1: length(@v);
- extract-1: extract(@v, 2);
- length-2: length(extract(@v, 2));
- extract-2: extract(extract(@v, 2), 2);
-
- &-as-args {.mixin-args(@a @b @c)}
-}
-
-.md-3D {
- @a: a b c d, 1 2 3 4;
- @b: 5 6 7 8, e f g h;
- .3D(@a, @b);
-
- .3D(...) {
-
- @v1: @arguments;
- length-1: length(@v1);
- extract-1: extract(@v1, 1);
-
- @v2: extract(@v1, 2);
- length-2: length(@v2);
- extract-2: extract(@v2, 1);
-
- @v3: extract(@v2, 1);
- length-3: length(@v3);
- extract-3: extract(@v3, 3);
-
- @v4: extract(@v3, 4);
- length-4: length(@v4);
- extract-4: extract(@v4, 1);
- }
-}
+++ /dev/null
-#functions {
- @var: 10;
- @colors: #000, #fff;
- color: _color("evil red"); // #660000
- width: increment(15);
- height: undefined("self");
- border-width: add(2, 3);
- variable: increment(@var);
- background: linear-gradient(@colors);
-}
-
-#built-in {
- @r: 32;
- escaped: e("-Some::weird(#thing, y)");
- lighten: lighten(#ff0000, 40%);
- darken: darken(#ff0000, 40%);
- saturate: saturate(#29332f, 20%);
- desaturate: desaturate(#203c31, 20%);
- greyscale: greyscale(#203c31);
- hsl-clamp: hsl(380, 150%, 150%);
- spin-p: spin(hsl(340, 50%, 50%), 40);
- spin-n: spin(hsl(30, 50%, 50%), -40);
- luma-white: luma(#fff);
- luma-black: luma(#000);
- luma-black-alpha: luma(rgba(0,0,0,0.5));
- luma-red: luma(#ff0000);
- luma-green: luma(#00ff00);
- luma-blue: luma(#0000ff);
- luma-yellow: luma(#ffff00);
- luma-cyan: luma(#00ffff);
- luma-white-alpha: luma(rgba(255,255,255,0.5));
- contrast-filter: contrast(30%);
- saturate-filter: saturate(5%);
- contrast-white: contrast(#fff);
- contrast-black: contrast(#000);
- contrast-red: contrast(#ff0000);
- contrast-green: contrast(#00ff00);
- contrast-blue: contrast(#0000ff);
- contrast-yellow: contrast(#ffff00);
- contrast-cyan: contrast(#00ffff);
- contrast-light: contrast(#fff, #111111, #eeeeee);
- contrast-dark: contrast(#000, #111111, #eeeeee);
- contrast-wrongorder: contrast(#fff, #eeeeee, #111111, 0.5);
- contrast-light-thresh: contrast(#fff, #111111, #eeeeee, 0.5);
- contrast-dark-thresh: contrast(#000, #111111, #eeeeee, 0.5);
- contrast-high-thresh: contrast(#555, #111111, #eeeeee, 0.6);
- contrast-low-thresh: contrast(#555, #111111, #eeeeee, 0.1);
- contrast-light-thresh-per: contrast(#fff, #111111, #eeeeee, 50%);
- contrast-dark-thresh-per: contrast(#000, #111111, #eeeeee, 50%);
- contrast-high-thresh-per: contrast(#555, #111111, #eeeeee, 60%);
- contrast-low-thresh-per: contrast(#555, #111111, #eeeeee, 10%);
- format: %("rgb(%d, %d, %d)", @r, 128, 64);
- format-string: %("hello %s", "world");
- format-multiple: %("hello %s %d", "earth", 2);
- format-url-encode: %('red is %A', #ff0000);
- eformat: e(%("rgb(%d, %d, %d)", @r, 128, 64));
-
- unitless: unit(12px);
- unit: unit((13px + 1px), em);
-
- hue: hue(hsl(98, 12%, 95%));
- saturation: saturation(hsl(98, 12%, 95%));
- lightness: lightness(hsl(98, 12%, 95%));
- hsvhue: hsvhue(hsv(98, 12%, 95%));
- hsvsaturation: hsvsaturation(hsv(98, 12%, 95%));
- hsvvalue: hsvvalue(hsv(98, 12%, 95%));
- red: red(#f00);
- green: green(#0f0);
- blue: blue(#00f);
- rounded: round((@r/3));
- rounded-two: round((@r/3), 2);
- roundedpx: round((10px / 3));
- roundedpx-three: round((10px / 3), 3);
- rounded-percentage: round(10.2%);
- ceil: ceil(10.1px);
- floor: floor(12.9px);
- sqrt: sqrt(25px);
- pi: pi();
- mod: mod(13m, 11cm); // could take into account units, doesn't at the moment
- abs: abs(-4%);
- tan: tan(42deg);
- sin: sin(10deg);
- cos: cos(12);
- atan: atan(tan(0.1rad));
- atan: convert(acos(cos(34deg)), deg);
- atan: convert(acos(cos(50grad)), deg);
- pow: pow(8px, 2);
- pow: pow(4, 3);
- pow: pow(3, 3em);
- min: min(0);
- min: min("junk", 6, 5);
- min: min(1pc, 3pt);
- max: max(1, 3);
- max: max(3%, 1cm, 8%, 2mm);
- percentage: percentage((10px / 50));
- color: color("#ff0011");
- tint: tint(#777777, 13);
- tint-full: tint(#777777, 100);
- tint-percent: tint(#777777, 13%);
- shade: shade(#777777, 13);
- shade-full: shade(#777777, 100);
- shade-percent: shade(#777777, 13%);
-
- fade-out: fadeOut(red, 5%); // support fadeOut and fadeout
- fade-in: fadein(fadeout(red, 10%), 5%);
-
- hsv: hsv(5, 50%, 30%);
- hsva: hsva(3, 50%, 30%, 0.2);
-
- mix: mix(#ff0000, #ffff00, 80);
- mix-0: mix(#ff0000, #ffff00, 0);
- mix-100: mix(#ff0000, #ffff00, 100);
- mix-weightless: mix(#ff0000, #ffff00);
- mixt: mix(#ff0000, transparent);
-
- .is-a {
- color: iscolor(#ddd);
- color1: iscolor(red);
- color2: iscolor(rgb(0, 0, 0));
- color3: iscolor(transparent);
- keyword: iskeyword(hello);
- number: isnumber(32);
- string: isstring("hello");
- pixel: ispixel(32px);
- percent: ispercentage(32%);
- em: isem(32em);
- cat: isunit(32cat, cat);
- }
-}
-
-#alpha {
- alpha: darken(hsla(25, 50%, 50%, 0.6), 10%);
- alpha2: alpha(rgba(3, 4, 5, 0.5));
- alpha3: alpha(transparent);
-}
-
-#blendmodes {
- multiply: multiply(#f60000, #f60000);
- screen: screen(#f60000, #0000f6);
- overlay: overlay(#f60000, #0000f6);
- softlight: softlight(#f60000, #ffffff);
- hardlight: hardlight(#f60000, #0000f6);
- difference: difference(#f60000, #0000f6);
- exclusion: exclusion(#f60000, #0000f6);
- average: average(#f60000, #0000f6);
- negation: negation(#f60000, #313131);
-}
-
-#extract-and-length {
- @anon: A B C 1 2 3;
- extract: extract(@anon, 6) extract(@anon, 5) extract(@anon, 4) extract(@anon, 3) extract(@anon, 2) extract(@anon, 1);
- length: length(@anon);
-}
+++ /dev/null
-@fat: 0;
-@cloudhead: "#000000";
-
-.nav {
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity = 20);
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@fat);
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#333333", endColorstr=@cloudhead, GradientType=@fat);
-}
-.evalTest(@arg) {
- filter: progid:DXImageTransform.Microsoft.Alpha(opacity=@arg);
-}
-.evalTest1 {
- .evalTest(30);
- .evalTest(5);
-}
\ No newline at end of file
+++ /dev/null
-@import (inline) url("import/import-test-d.css") (min-width:600px);
-@import (inline, css) url("import/invalid-css.less");
\ No newline at end of file
+++ /dev/null
-@my_theme: "test";
-
-@import "import/import-@{my_theme}-e.less";
-
-@import "import/import-@{in}@{terpolation}.less";
-
-@in: "in";
-@terpolation: "terpolation";
\ No newline at end of file
+++ /dev/null
-@import "import/import-once-test-c";
-@import "import/import-once-test-c";
-@import "import/import-once-test-c.less";
-@import "import/deeper/import-once-test-a";
-@import (multiple) "import/import-test-f.less";
-@import (multiple) "import/import-test-f.less";
\ No newline at end of file
+++ /dev/null
-@import (reference) url("import-once.less");
-@import (reference) url("css-3.less");
-@import (reference) url("media.less");
-/*
- The media statement above is invalid (no selector)
- We should ban invalid media queries with properties and no selector?
-*/
-@import (reference) url("import/import-reference.less");
-
-.b {
- .z();
-}
-
-.zz();
-
-.visible:extend(.z all) {
- extend: test;
-}
\ No newline at end of file
+++ /dev/null
-@import url(http://fonts.googleapis.com/css?family=Open+Sans);
-
-@import url(/absolute/something.css) screen and (color) and (max-width: 600px);
-
-@var: 100px;
-@import url("//ha.com/file.css") (min-width:@var);
-
-#import-test {
- .mixin;
- width: 10px;
- height: (@a + 10%);
-}
-@import "import/import-test-e" screen and (max-width: 600px);
-
-@import url("import/import-test-a.less");
-
-@import (less, multiple) "import/import-test-d.css" screen and (max-width: 601px);
-
-@import (multiple) "import/import-test-e" screen and (max-width: 602px);
-
-@import (less, multiple) url("import/import-test-d.css") screen and (max-width: 603px);
\ No newline at end of file
+++ /dev/null
-@import "../import-once-test-c";
\ No newline at end of file
+++ /dev/null
-@import "../css/background.css";
-@import "import-test-d.css";
-
-@import "imports/logo";
-@import "imports/font";
-
+++ /dev/null
-@charset "ISO-8859-1";
\ No newline at end of file
+++ /dev/null
-@import "import-@{in}@{terpolation}2.less";
\ No newline at end of file
+++ /dev/null
-.a {
- var: test;
-}
-
-@in: "redefined-does-nothing";
\ No newline at end of file
+++ /dev/null
-
-@c: red;
-
-#import {
- color: @c;
-}
+++ /dev/null
-.z {
- color: red;
- .c {
- color: green;
- }
-}
-.only-with-visible,
-.z {
- color: green;
- &:hover {
- color: green;
- }
- & {
- color: green;
- }
- & + & {
- color: green;
- .sub {
- color: green;
- }
- }
-}
-
-& {
- .hidden {
- hidden: true;
- }
-}
-
-@media tv {
- .hidden {
- hidden: true;
- }
-}
-
-/* comment is not output */
-
-.zz {
- .y {
- pulled-in: yes;
- }
- /* comment pulled in */
-}
\ No newline at end of file
+++ /dev/null
-@import "import-test-b.less";
-@a: 20%;
-@import "urls.less";
\ No newline at end of file
+++ /dev/null
-@import "import-test-c";
-
-@b: 100%;
-
-.mixin {
- height: 10px;
- color: @c;
-}
+++ /dev/null
-
-@c: red;
-
-#import {
- color: @c;
-}
+++ /dev/null
-#css { color: yellow; }
+++ /dev/null
-
-body { width: 100% }
+++ /dev/null
-@import "import-test-e";
-
-.test-f {
- height: 10px;
-}
+++ /dev/null
-@font-face {
- font-family: xecret;
- src: url('../assets/xecret.ttf');
-}
-
-#secret {
- font-family: xecret, sans-serif;
-}
+++ /dev/null
-#logo {
- width: 100px;
- height: 100px;
- background: url('../assets/logo.png');
-}
+++ /dev/null
-this isn't very valid CSS.
\ No newline at end of file
+++ /dev/null
-// empty file showing that it loads from the relative path first
+++ /dev/null
-.eval {
- js: `42`;
- js: `1 + 1`;
- js: `"hello world"`;
- js: `[1, 2, 3]`;
- title: `typeof process.title`;
- ternary: `(1 + 1 == 2 ? true : false)`;
- multiline: `(function(){var x = 1 + 1;
- return x})()`;
-}
-.scope {
- @foo: 42;
- var: `parseInt(this.foo.toJS())`;
- escaped: ~`2 + 5 + 'px'`;
-}
-.vars {
- @var: `4 + 4`;
- width: @var;
-}
-.escape-interpol {
- @world: "world";
- width: ~`"hello" + " " + @{world}`;
-}
-.arrays {
- @ary: 1, 2, 3;
- @ary2: 1 2 3;
- ary: `@{ary}.join(', ')`;
- ary1: `@{ary2}.join(', ')`;
-}
+++ /dev/null
-@var: @a;
-@a: 100%;
-
-.lazy-eval {
- width: @var;
-}
+++ /dev/null
-@media (-o-min-device-pixel-ratio: 2/1) {
- .test-math-and-units {
- font: ignores 0/0 rules;
- test-division: 4 / 2 + 5em;
- simple: 1px + 1px;
- }
-}
\ No newline at end of file
+++ /dev/null
-
-// For now, variables can't be declared inside @media blocks.
-
-@var: 42;
-
-@media print {
- .class {
- color: blue;
- .sub {
- width: @var;
- }
- }
- .top, header > h1 {
- color: (#222 * 2);
- }
-}
-
-@media screen {
- @base: 8;
- body { max-width: (@base * 60); }
-}
-
-@ratio_large: 16;
-@ratio_small: 9;
-
-@media all and (device-aspect-ratio: @ratio_large / @ratio_small) {
- body { max-width: 800px; }
-}
-
-@media all and (orientation:portrait) {
- aside { float: none; }
-}
-
-@media handheld and (min-width: @var), screen and (min-width: 20em) {
- body {
- max-width: 480px;
- }
-}
-
-body {
- @media print {
- padding: 20px;
-
- header {
- background-color: red;
- }
-
- @media (orientation:landscape) {
- margin-left: 20px;
- }
- }
-}
-
-@media screen {
- .sidebar {
- width: 300px;
- @media (orientation: landscape) {
- width: 500px;
- }
- }
-}
-
-@media a {
- .first {
- @media b {
- .second {
- .third {
- width: 300px;
- @media c {
- width: 500px;
- }
- }
- .fourth {
- width: 3;
- }
- }
- }
- }
-}
-
-body {
- @media a, b and c {
- width: 95%;
-
- @media x, y {
- width: 100%;
- }
- }
-}
-
-.mediaMixin(@fallback: 200px) {
- background: black;
-
- @media handheld {
- background: white;
-
- @media (max-width: @fallback) {
- background: red;
- }
- }
-}
-
-.a {
- .mediaMixin(100px);
-}
-
-.b {
- .mediaMixin();
-}
-@smartphone: ~"only screen and (max-width: 200px)";
-@media @smartphone {
- body {
- width: 480px;
- }
-}
-
-@media print {
- @page :left {
- margin: 0.5cm;
- }
- @page :right {
- margin: 0.5cm;
- }
- @page Test:first {
- margin: 1cm;
- }
- @page :first {
- size: 8.5in 11in;
- @top-left {
- margin: 1cm;
- }
- @top-left-corner {
- margin: 1cm;
- }
- @top-center {
- margin: 1cm;
- }
- @top-right {
- margin: 1cm;
- }
- @top-right-corner {
- margin: 1cm;
- }
- @bottom-left {
- margin: 1cm;
- }
- @bottom-left-corner {
- margin: 1cm;
- }
- @bottom-center {
- margin: 1cm;
- }
- @bottom-right {
- margin: 1cm;
- }
- @bottom-right-corner {
- margin: 1cm;
- }
- @left-top {
- margin: 1cm;
- }
- @left-middle {
- margin: 1cm;
- }
- @left-bottom {
- margin: 1cm;
- }
- @right-top {
- margin: 1cm;
- }
- @right-middle {
- content: "Page " counter(page);
- }
- @right-bottom {
- margin: 1cm;
- }
- }
-}
-
-@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (-o-min-device-pixel-ratio: 2/1), (min-resolution: 2dppx), (min-resolution: 128dpcm) {
- .b {
- background: red;
- }
-}
-
-.bg() {
- background: red;
-
- @media (max-width: 500px) {
- background: green;
- }
-}
-
-body {
- .bg();
-}
-
-@bpMedium: 1000px;
-@media (max-width: @bpMedium) {
- body {
- .bg();
- background: blue;
- }
-}
-
-@media (max-width: 1200px) {
- /* a comment */
-
- @media (max-width: 900px) {
- body { font-size: 11px; }
- }
-}
-
-.nav-justified {
- @media (min-width: 480px) {
- > li {
- display: table-cell;
- }
- }
-}
-
-.menu
-{
- @media (min-width: 768px) {
- .nav-justified();
- }
-}
-@all: ~"all";
-@tv: ~"tv";
-@media @all and @tv {
- .all-and-tv-variables {
- var: all-and-tv;
- }
-}
\ No newline at end of file
+++ /dev/null
-.first-transform() {
- transform+: rotate(90deg), skew(30deg);
-}
-.second-transform() {
- transform+: scale(2,4);
-}
-.third-transform() {
- transform: scaleX(45deg);
-}
-.fourth-transform() {
- transform+: scaleX(45deg);
-}
-.fifth-transform() {
- transform+: scale(2,4) !important;
-}
-.first-background() {
- background+: url(data://img1.png);
-}
-.second-background() {
- background+: url(data://img2.png);
-}
-
-.test1 {
- // Can merge values
- .first-transform();
- .second-transform();
-}
-.test2 {
- // Wont merge values without +: merge directive, for backwards compatibility with css
- .first-transform();
- .third-transform();
-}
-.test3 {
- // Wont merge values from two sources with different properties
- .fourth-transform();
- .first-background();
-}
-.test4 {
- // Wont merge values from sources that merked as !important, for backwards compatibility with css
- .first-transform();
- .fifth-transform();
-}
-.test5 {
- // Wont merge values from mixins that merked as !important, for backwards compatibility with css
- .first-transform();
- .second-transform() !important;
-}
-.test6 {
- // Ignores !merge if no peers found
- .second-transform();
-}
\ No newline at end of file
+++ /dev/null
-.mixin (@a: 1px, @b: 50%) {
- width: (@a * 5);
- height: (@b - 1%);
-}
-
-.mixina (@style, @width, @color: black) {
- border: @width @style @color;
-}
-
-.mixiny
-(@a: 0, @b: 0) {
- margin: @a;
- padding: @b;
-}
-
-.hidden() {
- color: transparent; // asd
-}
-
-#hidden {
- .hidden;
-}
-
-#hidden1 {
- .hidden();
-}
-
-.two-args {
- color: blue;
- .mixin(2px, 100%);
- .mixina(dotted, 2px);
-}
-
-.one-arg {
- .mixin(3px);
-}
-
-.no-parens {
- .mixin;
-}
-
-.no-args {
- .mixin();
-}
-
-.var-args {
- @var: 9;
- .mixin(@var, (@var * 2));
-}
-
-.multi-mix {
- .mixin(2px, 30%);
- .mixiny(4, 5);
-}
-
-.maxa(@arg1: 10, @arg2: #f00) {
- padding: (@arg1 * 2px);
- color: @arg2;
-}
-
-body {
- .maxa(15);
-}
-
-@glob: 5;
-.global-mixin(@a:2) {
- width: (@glob + @a);
-}
-
-.scope-mix {
- .global-mixin(3);
-}
-
-.nested-ruleset (@width: 200px) {
- width: @width;
- .column { margin: @width; }
-}
-.content {
- .nested-ruleset(600px);
-}
-
-//
-
-.same-var-name2(@radius) {
- radius: @radius;
-}
-.same-var-name(@radius) {
- .same-var-name2(@radius);
-}
-#same-var-name {
- .same-var-name(5px);
-}
-
-//
-
-.var-inside () {
- @var: 10px;
- width: @var;
-}
-#var-inside { .var-inside; }
-
-.mixin-arguments (@width: 0px, ...) {
- border: @arguments;
- width: @width;
-}
-
-.arguments {
- .mixin-arguments(1px, solid, black);
-}
-.arguments2 {
- .mixin-arguments();
-}
-.arguments3 {
- .mixin-arguments;
-}
-
-.mixin-arguments2 (@width, @rest...) {
- border: @arguments;
- rest: @rest;
- width: @width;
-}
-.arguments4 {
- .mixin-arguments2(0, 1, 2, 3, 4);
-}
-
-// Edge cases
-
-.edge-case {
- .mixin-arguments("{");
-}
-
-// Division vs. Literal Slash
-.border-radius(@r: 2px/5px) {
- border-radius: @r;
-}
-.slash-vs-math {
- .border-radius();
- .border-radius(5px/10px);
- .border-radius((3px * 2));
-}
-// semi-colon vs comma for delimiting
-
-.mixin-takes-one(@a) {
- one: @a;
-}
-
-.mixin-takes-two(@a; @b) {
- one: @a;
- two: @b;
-}
-
-.comma-vs-semi-colon {
- .mixin-takes-two(@a : a; @b : b, c);
- .mixin-takes-two(@a : d, e; @b : f);
- .mixin-takes-one(@a: g);
- .mixin-takes-one(@a : h;);
- .mixin-takes-one(i);
- .mixin-takes-one(j;);
- .mixin-takes-two(k, l);
- .mixin-takes-one(m, n;);
- .mixin-takes-two(o, p; q);
- .mixin-takes-two(r, s; t;);
-}
-
-.mixin-conflict(@a:defA, @b:defB, @c:defC) {
- three: @a, @b, @c;
-}
-
-.mixin-conflict(@a:defA, @b:defB, @c:defC, @d:defD) {
- four: @a, @b, @c, @d;
-}
-
-#named-conflict {
- .mixin-conflict(11, 12, 13, @a:a);
- .mixin-conflict(@a:a, 21, 22, 23);
-}
-@a: 3px;
-.mixin-default-arg(@a: 1px, @b: @a, @c: @b) {
- defaults: 1px 1px 1px;
- defaults: 2px 2px 2px;
-}
-
-.test-mixin-default-arg {
- .mixin-default-arg();
- .mixin-default-arg(2px);
-}
-
-.mixin-comma-default1(@color; @padding; @margin: 2, 2, 2, 2) {
- margin: @margin;
-}
-.selector {
- .mixin-comma-default1(#33acfe; 4);
-}
-.mixin-comma-default2(@margin: 2, 2, 2, 2;) {
- margin: @margin;
-}
-.selector2 {
- .mixin-comma-default2();
-}
-.mixin-comma-default3(@margin: 2, 2, 2, 2) {
- margin: @margin;
-}
-.selector3 {
- .mixin-comma-default3(4,2,2,2);
-}
-
-.test-calling-one-arg-mixin(@a) {
-}
-
-.test-calling-one-arg-mixin(@a, @b, @rest...) {
-}
-
-div {
- .test-calling-one-arg-mixin(1);
-}
\ No newline at end of file
+++ /dev/null
-.scope {
- @var: 99px;
- .mixin () {
- width: @var;
- }
-}
-
-.class {
- .scope > .mixin;
-}
-
-.overwrite {
- @var: 0px;
- .scope > .mixin;
-}
-
-.nested {
- @var: 5px;
- .mixin () {
- width: @var;
- }
- .class {
- @var: 10px;
- .mixin;
- }
-}
+++ /dev/null
-
-// Stacking, functions..
-
-.light (@a) when (lightness(@a) > 50%) {
- color: white;
-}
-.light (@a) when (lightness(@a) < 50%) {
- color: black;
-}
-.light (@a) {
- margin: 1px;
-}
-
-.light1 { .light(#ddd) }
-.light2 { .light(#444) }
-
-// Arguments against each other
-
-.max (@a, @b) when (@a > @b) {
- width: @a;
-}
-.max (@a, @b) when (@a < @b) {
- width: @b;
-}
-
-.max1 { .max(3, 6) }
-.max2 { .max(8, 1) }
-
-// Globals inside guards
-
-@g: auto;
-
-.glob (@a) when (@a = @g) {
- margin: @a @g;
-}
-.glob1 { .glob(auto) }
-
-// Other operators
-
-.ops (@a) when (@a >= 0) {
- height: gt-or-eq;
-}
-.ops (@a) when (@a =< 0) {
- height: lt-or-eq;
-}
-.ops (@a) when (@a <= 0) {
- height: lt-or-eq-alias;
-}
-.ops (@a) when not(@a = 0) {
- height: not-eq;
-}
-.ops1 { .ops(0) }
-.ops2 { .ops(1) }
-.ops3 { .ops(-1) }
-
-// Scope and default values
-
-@a: auto;
-
-.default (@a: inherit) when (@a = inherit) {
- content: default;
-}
-.default1 { .default }
-
-// true & false keywords
-.test (@a) when (@a) {
- content: "true.";
-}
-.test (@a) when not (@a) {
- content: "false.";
-}
-
-.test1 { .test(true) }
-.test2 { .test(false) }
-.test3 { .test(1) }
-.test4 { .test(boo) }
-.test5 { .test("true") }
-
-// Boolean expressions
-
-.bool () when (true) and (false) { content: true and false } // FALSE
-.bool () when (true) and (true) { content: true and true } // TRUE
-.bool () when (true) { content: true } // TRUE
-.bool () when (false) and (false) { content: true } // FALSE
-.bool () when (false), (true) { content: false, true } // TRUE
-.bool () when (false) and (true) and (true), (true) { content: false and true and true, true } // TRUE
-.bool () when (true) and (true) and (false), (false) { content: true and true and false, false } // FALSE
-.bool () when (false), (true) and (true) { content: false, true and true } // TRUE
-.bool () when (false), (false), (true) { content: false, false, true } // TRUE
-.bool () when (false), (false) and (true), (false) { content: false, false and true, false } // FALSE
-.bool () when (false), (true) and (true) and (true), (false) { content: false, true and true and true, false } // TRUE
-.bool () when not (false) { content: not false }
-.bool () when not (true) and not (false) { content: not true and not false }
-.bool () when not (true) and not (true) { content: not true and not true }
-.bool () when not (false) and (false), not (false) { content: not false and false, not false }
-
-.bool1 { .bool }
-
-.equality-unit-test(@num) when (@num = 1%) {
- test: fail;
-}
-.equality-unit-test(@num) when (@num = 2) {
- test: pass;
-}
-.equality-units {
- .equality-unit-test(1px);
- .equality-unit-test(2px);
-}
-
-.colorguard(@col) when (@col = red) { content: is @col; }
-.colorguard(@col) when not (blue = @col) { content: is not blue its @col; }
-.colorguard(@col) {}
-.colorguardtest {
- .colorguard(red);
- .colorguard(blue);
- .colorguard(purple);
-}
-
-.stringguard(@str) when (@str = "theme1") { content: is theme1; }
-.stringguard(@str) when not ("theme2" = @str) { content: is not theme2; }
-.stringguard(@str) when (~"theme1" = @str) { content: is theme1 no quotes; }
-.stringguard(@str) {}
-.stringguardtest {
- .stringguard("theme1");
- .stringguard("theme2");
- .stringguard(theme1);
-}
-
-.mixin(...) {
- catch:all;
-}
-.mixin(@var) when (@var=4) {
- declare: 4;
-}
-.mixin(@var) when (@var=4px) {
- declare: 4px;
-}
-#tryNumberPx {
- .mixin(4px);
-}
-
-.lock-mixin(@a) {
- .inner-locked-mixin(@x: @a) when (@a = 1) {
- a: @a;
- x: @x;
- }
-}
-.call-lock-mixin {
- .lock-mixin(1);
- .call-inner-lock-mixin {
- .inner-locked-mixin();
- }
-}
\ No newline at end of file
+++ /dev/null
-.submixin(@a) {
- border-width: @a;
-}
-.mixin (9) {
- border: 9 !important;
-}
-.mixin (@a: 0) {
- border: @a;
- boxer: @a;
- .inner {
- test: @a;
- }
- // comment
- .submixin(@a);
-}
-
-.class {
- .mixin(1);
- .mixin(2) !important;
- .mixin(3);
- .mixin(4) !important;
- .mixin(5);
- .mixin !important;
- .mixin(9);
-}
+++ /dev/null
-.mixin (@a: 1px, @b: 50%) {
- width: (@a * 5);
- height: (@b - 1%);
- args: @arguments;
-}
-.mixin (@a: 1px, @b: 50%) when (@b > 75%){
- text-align: center;
-}
-
-.named-arg {
- color: blue;
- .mixin(@b: 100%);
-}
-
-.class {
- @var: 20%;
- .mixin(@b: @var);
-}
-
-.all-args-wrong-args {
- .mixin(@b: 10%, @a: 2px);
-}
-
-.mixin2 (@a: 1px, @b: 50%, @c: 50) {
- width: (@a * 5);
- height: (@b - 1%);
- color: (#000000 + @c);
-}
-
-.named-args2 {
- .mixin2(3px, @c: 100);
-}
-
-.named-args3 {
- .mixin2(@b: 30%, @c: #123456);
-}
\ No newline at end of file
+++ /dev/null
-.mix-inner (@var) {
- border-width: @var;
-}
-
-.mix (@a: 10) {
- .inner {
- height: (@a * 10);
-
- .innest {
- width: @a;
- .mix-inner((@a * 2));
- }
- }
-}
-
-.class {
- .mix(30);
-}
-
-.class2 {
- .mix(60);
-}
+++ /dev/null
-.mixin (...) {
- variadic: true;
-}
-.mixin () {
- zero: 0;
-}
-.mixin (@a: 1px) {
- one: 1;
-}
-.mixin (@a) {
- one-req: 1;
-}
-.mixin (@a: 1px, @b: 2px) {
- two: 2;
-}
-
-.mixin (@a, @b, @c) {
- three-req: 3;
-}
-
-.mixin (@a: 1px, @b: 2px, @c: 3px) {
- three: 3;
-}
-
-.zero {
- .mixin();
-}
-
-.one {
- .mixin(1);
-}
-
-.two {
- .mixin(1, 2);
-}
-
-.three {
- .mixin(1, 2, 3);
-}
-
-//
-
-.mixout ('left') {
- left: 1;
-}
-
-.mixout ('right') {
- right: 1;
-}
-
-.left {
- .mixout('left');
-}
-.right {
- .mixout('right');
-}
-
-//
-
-.border (@side, @width) {
- color: black;
- .border-side(@side, @width);
-}
-.border-side (left, @w) {
- border-left: @w;
-}
-.border-side (right, @w) {
- border-right: @w;
-}
-
-.border-right {
- .border(right, 4px);
-}
-.border-left {
- .border(left, 4px);
-}
-
-//
-
-
-.border-radius (@r) {
- both: (@r * 10);
-}
-.border-radius (@r, left) {
- left: @r;
-}
-.border-radius (@r, right) {
- right: @r;
-}
-
-.only-right {
- .border-radius(33, right);
-}
-.only-left {
- .border-radius(33, left);
-}
-.left-right {
- .border-radius(33);
-}
+++ /dev/null
-.mixin { border: 1px solid black; }
-.mixout { border-color: orange; }
-.borders { border-style: dashed; }
-
-#namespace {
- .borders {
- border-style: dotted;
- }
- .biohazard {
- content: "death";
- .man {
- color: transparent;
- }
- }
-}
-#theme {
- > .mixin {
- background-color: grey;
- }
-}
-#container {
- color: black;
- .mixin;
- .mixout;
- #theme > .mixin;
-}
-
-#header {
- .milk {
- color: white;
- .mixin;
- #theme > .mixin;
- }
- #cookie {
- .chips {
- #namespace .borders;
- .calories {
- #container;
- }
- }
- .borders;
- }
-}
-.secure-zone { #namespace .biohazard .man; }
-.direct {
- #namespace > .borders;
-}
-
-.bo, .bar {
- width: 100%;
-}
-.bo {
- border: 1px;
-}
-.ar.bo.ca {
- color: black;
-}
-.jo.ki {
- background: none;
-}
-.amp {
- &.support {
- color: orange;
- .higher {
- top: 0px;
- }
- &.deeper {
- height: auto;
- }
- }
-}
-.extended {
- .bo;
- .jo.ki;
- .amp.support;
- .amp.support.higher;
- .amp.support.deeper;
-}
-.do .re .mi .fa {
- .sol .la {
- .si {
- color: cyan;
- }
- }
-}
-.mutli-selector-parents {
- .do.re.mi.fa.sol.la.si;
-}
-.foo .bar {
- .bar;
-}
-.has_parents() {
- & .underParents {
- color: red;
- }
-}
-.has_parents();
-.parent {
- .has_parents();
-}
-.margin_between(@above, @below) {
- * + & { margin-top: @above; }
- legend + & { margin-top: 0; }
- & + * { margin-top: @below; }
-}
-h1 { .margin_between(25px, 10px); }
-h2 { .margin_between(20px, 8px); }
-h3 { .margin_between(15px, 5px); }
-
-.mixin_def(@url, @position){
- background-image: @url;
- background-position: @position;
-}
-.error{
- @s: "/";
- .mixin_def( "@{s}a.png", center center);
-}
-.recursion() {
- color: black;
-}
-.test-rec {
- .recursion {
- .recursion();
- }
-}
-.paddingFloat(@padding) { padding-left: @padding; }
-
-.button {
- .paddingFloat(((10px + 12) * 2));
-
- &.large { .paddingFloat(((10em * 2) * 2)); }
-}
-.clearfix() {
- // ...
-}
-.clearfix {
- .clearfix();
-}
-.foo {
- .clearfix();
-}
\ No newline at end of file
+++ /dev/null
-.a {
- a: `1 + 1`;
-}
\ No newline at end of file
+++ /dev/null
-SyntaxError: You are using JavaScript, which has been disabled. in {path}no-js-errors.less on line 2, column 6:
-1 .a {
-2 a: `1 + 1`;
-3 }
+++ /dev/null
-.mixin() {
-}
\ No newline at end of file
+++ /dev/null
-#operations {
- color: (#110000 + #000011 + #001100); // #111111
- height: (10px / 2px + 6px - 1px * 2); // 9px
- width: (2 * 4 - 5em); // 3em
- .spacing {
- height: (10px / 2px+6px-1px*2);
- width: (2 * 4-5em);
- }
- substraction: (20 - 10 - 5 - 5); // 0
- division: (20 / 5 / 4); // 1
-}
-
-@x: 4;
-@y: 12em;
-
-.with-variables {
- height: (@x + @y); // 16em
- width: (12 + @y); // 24em
- size: (5cm - @x); // 1cm
-}
-
-.with-functions {
- color: (rgb(200, 200, 200) / 2);
- color: (2 * hsl(0, 50%, 50%));
- color: (rgb(10, 10, 10) + hsl(0, 50%, 50%));
-}
-
-@z: -2;
-
-.negative {
- height: (2px + @z); // 0px
- width: (2px - @z); // 4px
-}
-
-.shorthands {
- padding: -1px 2px 0 -4px; //
-}
-
-.rem-dimensions {
- font-size: (20rem / 5 + 1.5rem); // 5.5rem
-}
-
-.colors {
- color: #123; // #112233
- border-color: (#234 + #111111); // #334455
- background-color: (#222222 - #fff); // #000000
- .other {
- color: (2 * #111); // #222222
- border-color: (#333333 / 3 + #111); // #222222
- }
-}
-
-.negations {
- @var: 4px;
- variable: (-@var); // 4
- variable1: (-@var + @var); // 0
- variable2: (@var + -@var); // 0
- variable3: (@var - -@var); // 8
- variable4: (-@var - -@var); // 0
- paren: (-(@var)); // -4px
- paren2: (-(2 + 2) * -@var); // 16
-}
+++ /dev/null
-.parens {
- @var: 1px;
- border: (@var * 2) solid black;
- margin: (@var * 1) (@var + 2) (4 * 4) 3;
- width: (6 * 6);
- padding: 2px (6 * 6px);
-}
-
-.more-parens {
- @var: (2 * 2);
- padding: (2 * @var) 4 4 (@var * 1px);
- width-all: ((@var * @var) * 6);
- width-first: ((@var * @var)) * 6;
- width-keep: (@var * @var) * 6;
- height-keep: (7 * 7) + (8 * 8);
- height-all: ((7 * 7) + (8 * 8));
- height-parts: ((7 * 7)) + ((8 * 8));
- margin-keep: (4 * (5 + 5) / 2) - (@var * 2);
- margin-parts: ((4 * (5 + 5) / 2)) - ((@var * 2));
- margin-all: ((4 * (5 + 5) / 2) + (-(@var * 2)));
- border-radius-keep: 4px * (1 + 1) / @var + 3px;
- border-radius-parts: ((4px * (1 + 1))) / ((@var + 3px));
- border-radius-all: (4px * (1 + 1) / @var + 3px);
- //margin: (6 * 6)px;
-}
-
-.negative {
- @var: 1;
- neg-var: -@var; // -1 ?
- neg-var-paren: -(@var); // -(1) ?
-}
-
-.nested-parens {
- width: 2 * (4 * (2 + (1 + 6))) - 1;
- height: ((2 + 3) * (2 + 3) / (9 - 4)) + 1;
-}
-
-.mixed-units {
- margin: 2px 4em 1 5pc;
- padding: (2px + 4px) 1em 2px 2;
-}
+++ /dev/null
-#first > .one {
- > #second .two > #deux {
- width: 50%;
- #third {
- &:focus {
- color: black;
- #fifth {
- > #sixth {
- .seventh #eighth {
- + #ninth {
- color: purple;
- }
- }
- }
- }
- }
- height: 100%;
- }
- #fourth, #five, #six {
- color: #110000;
- .seven, .eight > #nine {
- border: 1px solid black;
- }
- #ten {
- color: red;
- }
- }
- }
- font-size: 2em;
-}
+++ /dev/null
-@x: red;
-@x: blue;
-@z: transparent;
-@mix: none;
-
-.mixin {
- @mix: #989;
-}
-@mix: blue;
-.tiny-scope {
- color: @mix; // #989
- .mixin;
-}
-
-.scope1 {
- @y: orange;
- @z: black;
- color: @x; // blue
- border-color: @z; // black
- .hidden {
- @x: #131313;
- }
- .scope2 {
- @y: red;
- color: @x; // blue
- .scope3 {
- @local: white;
- color: @y; // red
- border-color: @z; // black
- background-color: @local; // white
- }
- }
-}
-
-#namespace {
- .scoped_mixin() {
- @local-will-be-made-global: green;
- .scope {
- scoped-val: @local-will-be-made-global;
- }
- }
-}
-
-#namespace > .scoped_mixin();
-
-.setHeight(@h) { @height: 1024px; }
-.useHeightInMixinCall(@h) { .useHeightInMixinCall { mixin-height: @h; } }
-@mainHeight: 50%;
-.setHeight(@mainHeight);
-.heightIsSet { height: @height; }
-.useHeightInMixinCall(@height);
-
-.importRuleset() {
- .imported {
- exists: true;
- }
-}
-.importRuleset();
-.testImported {
- .imported;
-}
-
-@parameterDefault: 'top level';
-@anotherVariable: 'top level';
-//mixin uses top-level variables
-.mixinNoParam(@parameter: @parameterDefault) when (@parameter = 'top level') {
- default: @parameter;
- scope: @anotherVariable;
- sub-scope-only: @subScopeOnly;
-}
-
-#allAreUsedHere {
- //redefine top-level variables in different scope
- @parameterDefault: 'inside';
- @anotherVariable: 'inside';
- @subScopeOnly: 'inside';
- //use the mixin
- .mixinNoParam();
-}
\ No newline at end of file
+++ /dev/null
-h1, h2, h3 {
- a, p {
- &:hover {
- color: red;
- }
- }
-}
-
-#all { color: blue; }
-#the { color: blue; }
-#same { color: blue; }
-
-ul, li, div, q, blockquote, textarea {
- margin: 0;
-}
-
-td {
- margin: 0;
- padding: 0;
-}
-
-td, input {
- line-height: 1em;
-}
-
-a {
- color: red;
-
- &:hover { color: blue; }
-
- div & { color: green; }
-
- p & span { color: yellow; }
-}
-
-.foo {
- .bar, .baz {
- & .qux {
- display: block;
- }
- .qux & {
- display: inline;
- }
- .qux& {
- display: inline-block;
- }
- .qux & .biz {
- display: none;
- }
- }
-}
-
-.b {
- &.c {
- .a& {
- color: red;
- }
- }
-}
-
-.b {
- .c & {
- &.a {
- color: red;
- }
- }
-}
-
-.p {
- .foo &.bar {
- color: red;
- }
-}
-
-.p {
- .foo&.bar {
- color: red;
- }
-}
-
-.foo {
- .foo + & {
- background: amber;
- }
- & + & {
- background: amber;
- }
-}
-
-.foo, .bar {
- & + & {
- background: amber;
- }
-}
-
-.foo, .bar {
- a, b {
- & > & {
- background: amber;
- }
- }
-}
-
-.other ::fnord { color: red }
-.other::fnord { color: red }
-.other {
- ::bnord {color: red }
- &::bnord {color: red }
-}
-// selector interpolation
-@theme: blood;
-@selector: ~".@{theme}";
-@{selector} {
- color:red;
-}
-@{selector}red {
- color: green;
-}
-.red {
- #@{theme}.@{theme}&.black {
- color:black;
- }
-}
-@num: 3;
-:nth-child(@{num}) {
- selector: interpolated;
-}
-.test {
- &:nth-child(odd):not(:nth-child(3)) {
- color: #ff0000;
- }
-}
-[prop],
-[prop=10%],
-[prop="value@{num}"],
-[prop*="val@{num}"],
-[|prop~="val@{num}"],
-[*|prop$="val@{num}"],
-[ns|prop^="val@{num}"],
-[@{num}^="val@{num}"],
-[@{num}=@{num}],
-[@{num}] {
- attributes: yes;
-}
\ No newline at end of file
+++ /dev/null
-@var: black;
-
-.a() {
- color: red;
-}
-
-.b {
- color: green;
- .a();
- color: blue;
- background: @var;
-}
-
-.a, .b {
- background: green;
- .c, .d {
- background: gray;
- & + & {
- color: red;
- }
- }
-}
-
-.extend:extend(.a all) {
- color: pink;
-}
-@import (inline) "imported.css";
\ No newline at end of file
+++ /dev/null
-/*comments*/
-.unused-css {
- color: white;
-}
-.imported {
- color: black;
-}
\ No newline at end of file
+++ /dev/null
-@font-face {
- src: local(Futura-Medium),
- url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
-}
-
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- @a: 'Trebuchet';
- url: url(@a);
-}
-
-@import "../import/import-and-relative-paths-test";
+++ /dev/null
-#strings {
- background-image: url("http://son-of-a-banana.com");
- quotes: "~" "~";
- content: "#*%:&^,)!.(~*})";
- empty: "";
- brackets: "{" "}";
- escapes: "\"hello\" \\world";
- escapes2: "\"llo";
-}
-#comments {
- content: "/* hello */ // not-so-secret";
-}
-#single-quote {
- quotes: "'" "'";
- content: '""#!&""';
- empty: '';
- semi-colon: ';';
-}
-#escaped {
- filter: ~"DX.Transform.MS.BS.filter(opacity=50)";
-}
-#one-line { image: url(http://tooks.com) }
-#crazy { image: url(http://), "}", url("http://}") }
-#interpolation {
- @var: '/dev';
- url: "http://lesscss.org@{var}/image.jpg";
-
- @var2: 256;
- url2: "http://lesscss.org/image-@{var2}.jpg";
-
- @var3: #456;
- url3: "http://lesscss.org@{var3}";
-
- @var4: hello;
- url4: "http://lesscss.org/@{var4}";
-
- @var5: 54.4px;
- url5: "http://lesscss.org/@{var5}";
-}
-
-// multiple calls with string interpolation
-
-.mix-mul (@a: green) {
- color: ~"@{a}";
-}
-.mix-mul-class {
- .mix-mul(blue);
- .mix-mul(red);
- .mix-mul(black);
- .mix-mul(orange);
-}
-
-@test: Arial, Verdana, San-Serif;
-.watermark {
- @family: ~"Univers, @{test}";
- family: @family;
-}
+++ /dev/null
-@font-face {
- src: local(Futura-Medium),
- url(fonts.svg#MyGeometricModern) format("svg");
-}
-#shorthands {
- background: url("http://www.lesscss.org/spec.html") no-repeat 0 4px;
- background: url("img.jpg") center / 100px;
- background: #fff url(image.png) center / 1px 100px repeat-x scroll content-box padding-box;
-}
-#misc {
- background-image: url(images/image.jpg);
-}
-#data-uri {
- background: url(data:image/png;charset=utf-8;base64,
- kiVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD/
- k//+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4U
- kg9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC);
- background-image: url(data:image/x-png,f9difSSFIIGFIFJD1f982FSDKAA9==);
- background-image: url(http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700);
- background-image: url("http://fonts.googleapis.com/css?family=\"Rokkitt\":\(400\),700");
-}
-
-#svg-data-uri {
- background: transparent url('data:image/svg+xml, <svg version="1.1"><g></g></svg>');
-}
-
-.comma-delimited {
- background: url(bg.jpg) no-repeat, url(bg.png) repeat-x top left, url(bg);
-}
-.values {
- @a: 'Trebuchet';
- url: url(@a);
-}
-
-@import "import/import-and-relative-paths-test";
-
-#data-uri {
- uri: data-uri('image/jpeg;base64', '../data/image.jpg');
-}
-
-#data-uri-guess {
- uri: data-uri('../data/image.jpg');
-}
-
-#data-uri-ascii {
- uri-1: data-uri('text/html', '../data/page.html');
- uri-2: data-uri('../data/page.html');
-}
-
-#data-uri-toobig {
- uri: data-uri('../data/data-uri-fail.png');
-}
-.add_an_import(@file_to_import) {
-@import "@{file_to_import}";
-}
-
-.add_an_import("file.css");
-
-#svg-functions {
- background-image: svg-gradient(to bottom, black, white);
- background-image: svg-gradient(to bottom, black, orange 3%, white);
- @green_5: green 5%;
- @orange_percentage: 3%;
- @orange_color: orange;
- background-image: svg-gradient(to bottom, (mix(black, white) + #444) 1%, @orange_color @orange_percentage, ((@green_5)), white 95%);
-}
+++ /dev/null
-@a: 2;
-@x: (@a * @a);
-@y: (@x + 1);
-@z: (@x * 2 + @y);
-@var: -1;
-
-.variables {
- width: (@z + 1cm); // 14cm
-}
-
-@b: @a * 10;
-@c: #888;
-
-@fonts: "Trebuchet MS", Verdana, sans-serif;
-@f: @fonts;
-
-@quotes: "~" "~";
-@q: @quotes;
-@onePixel: 1px;
-
-.variables {
- height: (@b + @x + 0px); // 24px
- color: @c;
- font-family: @f;
- quotes: @q;
-}
-
-.redef {
- @var: 0;
- .inition {
- @var: 4;
- @var: 2;
- three: @var;
- @var: 3;
- }
- zero: @var;
-}
-
-.values {
- minus-one: @var;
- @a: 'Trebuchet';
- @multi: 'A', B, C;
- font-family: @a, @a, @a;
- color: @c !important;
- multi: something @multi, @a;
-}
-
-.variable-names {
- @var: 'hello';
- @name: 'var';
- name: @@name;
-}
-
-.alpha {
- @var: 42;
- filter: alpha(opacity=@var);
-}
-
-.polluteMixin() {
- @a: 'pollution';
-}
-.testPollution {
- @a: 'no-pollution';
- a: @a;
- .polluteMixin();
- a: @a;
-}
-
-.units {
- width: @onePixel;
- same-unit-as-previously: (@onePixel / @onePixel);
- square-pixel-divided: (@onePixel * @onePixel / @onePixel);
- odd-unit: unit((@onePixel * 4em / 2cm));
- percentage: (10 * 50%);
- pixels: (50px * 10);
- conversion-metric-a: (20mm + 1cm);
- conversion-metric-b: (1cm + 20mm);
- conversion-imperial: (1in + 72pt + 6pc);
- custom-unit: (42octocats * 10);
- custom-unit-cancelling: (8cats * 9dogs / 4cats);
- mix-units: (1px + 1em);
- invalid-units: (1px * 1px);
-}
+++ /dev/null
-
-
-.whitespace
- { color: white; }
-
-.whitespace
-{
- color: white;
-}
- .whitespace
-{ color: white; }
-
-.whitespace{color:white;}
-.whitespace { color : white ; }
-
-.white,
-.space,
-.mania
-{ color: white; }
-
-.no-semi-column { color: white }
-.no-semi-column {
- color: white;
- white-space: pre
-}
-.no-semi-column {border: 2px solid white}
-.newlines {
- background: the,
- great,
- wall;
- border: 2px
- solid
- black;
-}
-.empty {
-
-}
-.sel
-.newline_ws .tab_ws {
-color:
-white;
-background-position: 45
--23;
-}
+++ /dev/null
-{"version":3,"file":"sourcemaps/basic.css","sources":["testweb/sourcemaps/imported.css","testweb/sourcemaps/basic.less"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;ACAG;EACD,YAAA;EAJA,UAAA;EAWA,iBAAA;EALA,WAAA;EACA,mBAAA;;AAJC,EASC;AATD,EASM;EACL,gBAAA;;AACE,EAFF,GAEM,KAFN;AAEE,EAFF,GAEM,KAFD;AAEH,EAFG,GAEC,KAFN;AAEE,EAFG,GAEC,KAFD;EAGH,UAAA;;AALJ;AAAK;AAUA;EATL,iBAAA;;AADA,EAEE;AAFG,EAEH;AAFF,EAEO;AAFF,EAEE;AAQF,OARH;AAQG,OARE;EACL,gBAAA;;AACE,EAFF,GAEM,KAFN;AAEE,EAFF,GAEM,KAFN;AAEE,EAFF,GAEM,KAFD;AAEH,EAFF,GAEM,KAFD;AAEH,EAFF,GAEM,KAFN;AAEE,EAFF,GAEM,KAFN;AAEE,EAFF,GAEM,KAFD;AAEH,EAFF,GAEM,KAFD;AAEH,EAFG,GAEC,KAFN;AAEE,EAFG,GAEC,KAFN;AAEE,EAFG,GAEC,KAFD;AAEH,EAFG,GAEC,KAFD;AAEH,EAFG,GAEC,KAFN;AAEE,EAFG,GAEC,KAFN;AAEE,EAFG,GAEC,KAFD;AAEH,EAFG,GAEC,KAFD;AAQF,OARH,GAQG,UARH;AAQG,OARH,GAEM,KAFN;AAQG,OARH,GAQG,UARE;AAQF,OARH,GAEM,KAFD;AAEH,EAFF,GAQG,UARH;AAEE,EAFF,GAQG,UARE;AAQF,OARE,GAQF,UARH;AAQG,OARE,GAEC,KAFN;AAQG,OARE,GAQF,UARE;AAQF,OARE,GAEC,KAFD;AAEH,EAFG,GAQF,UARH;AAEE,EAFG,GAQF,UARE;EAGH,UAAA;;AAKC;EACL,WAAA"}
\ No newline at end of file
+++ /dev/null
-<html>
- <link type="text/css" rel="stylesheet" media="all" href="import.css">
- <link type="text/css" rel="stylesheet" media="all" href="basic.css">
-<head>
-</head>
-<body>
-<div id="import-test">id import-test</div>
-<div id="import">id import-test</div>
-<div class="imported inline">class imported inline</div>
-<div id="mixin">class mixin</div>
-<div class="a">class a</div>
-<div class="b">class b</div>
-<div class="b">class b<div class="c">class c</div></div>
-<div class="a">class a<div class="d">class d</div></div>
-<div class="extend">class extend<div class="c">class c</div></div>
-</body>
-</html>
\ No newline at end of file
+++ /dev/null
-body{color:#fff}
\ No newline at end of file
+++ /dev/null
-body{color:#fff}#header{background:#fff}#footer{color:#377;background:#233}
\ No newline at end of file
+++ /dev/null
-body{color:#fff}
\ No newline at end of file
+++ /dev/null
-body {
- color: #ffffff;
-}
-
-#header {
- background: #ffffff;
-}
-
-#footer {
- color: #377;
- background: #233;
-}
+++ /dev/null
-.myRule {
- background-color: red;
- width: 5px;
- background: "Hello";
-}
+++ /dev/null
-body {
- width: 288px;
- height: 288px;
- background: transparent url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAAwADAAD/7RtYUGhvdG9zaG9wIDMuMAA4QklNBCUAAAAAABAAAAAAAAAAAAAAAAAAAAAAOEJJTQPtAAAAAAAQAAMAAAABAAEAAwAAAAEAAThCSU0EJgAAAAAADgAAAAAAAAAAAAA/gAAAOEJJTQQNAAAAAAAEAAAAHjhCSU0EGQAAAAAABAAAAB44QklNA/MAAAAAAAkAAAAAAAAAAAEAOEJJTQQKAAAAAAABAAA4QklNJxAAAAAAAAoAAQAAAAAAAAACOEJJTQP1AAAAAABIAC9mZgABAGxmZgAGAAAAAAABAC9mZgABAKGZmgAGAAAAAAABADIAAAABAFoAAAAGAAAAAAABADUAAAABAC0AAAAGAAAAAAABOEJJTQP4AAAAAABwAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAADhCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAANlAAAABgAAAAAAAAAAAAACKAAABAAAAAAYAEgAYQBwAHAAeQAtAEcAaQBsAG0AbwByAGUALQBCAG8AYgAtAEIAYQByAGsAZQByAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAQAAAACKAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAABAAAAABAAAAAAAAbnVsbAAAAAIAAAAGYm91bmRzT2JqYwAAAAEAAAAAAABSY3QxAAAABAAAAABUb3AgbG9uZwAAAAAAAAAATGVmdGxvbmcAAAAAAAAAAEJ0b21sb25nAAACKAAAAABSZ2h0bG9uZwAABAAAAAAGc2xpY2VzVmxMcwAAAAFPYmpjAAAAAQAAAAAABXNsaWNlAAAAEgAAAAdzbGljZUlEbG9uZwAAAAAAAAAHZ3JvdXBJRGxvbmcAAAAAAAAABm9yaWdpbmVudW0AAAAMRVNsaWNlT3JpZ2luAAAADWF1dG9HZW5lcmF0ZWQAAAAAVHlwZWVudW0AAAAKRVNsaWNlVHlwZQAAAABJbWcgAAAA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MjoxMi0wNDowMDwveGFwOk1vZGlmeURhdGU+CiAgICAgICAgIDx4YXA6TWV0YWRhdGFEYXRlPjIwMTAtMDYtMTVUMDg6MzI6MTItMDQ6MDA8L3hhcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDx4YXA6Q3JlYXRvclRvb2w+QWRvYmUgUGhvdG9zaG9wIENTMiBXaW5kb3dzPC94YXA6Q3JlYXRvclRvb2w+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iPgogICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL2pwZWc8L2RjOmZvcm1hdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyI+CiAgICAgICAgIDxwaG90b3Nob3A6Q29sb3JNb2RlPjM8L3Bob3Rvc2hvcDpDb2xvck1vZGU+CiAgICAgICAgIDxwaG90b3Nob3A6SGlzdG9yeS8+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjMwMDAwLzEwMDAwPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj4zMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPHRpZmY6TmF0aXZlRGlnZXN0PjI1NiwyNTcsMjU4LDI1OSwyNjIsMjc0LDI3NywyODQsNTMwLDUzMSwyODIsMjgzLDI5NiwzMDEsMzE4LDMxOSw1MjksNTMyLDMwNiwyNzAsMjcxLDI3MiwzMDUsMzE1LDMzNDMyOzE1QjRFQUJBOEQ5RTYyMDlCRDJDMjU5REVDODdDOTdDPC90aWZmOk5hdGl2ZURpZ2VzdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjEwMjQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+NTUyPC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT4tMTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpOYXRpdmVEaWdlc3Q+MzY4NjQsNDA5NjAsNDA5NjEsMzcxMjEsMzcxMjIsNDA5NjIsNDA5NjMsMzc1MTAsNDA5NjQsMzY4NjcsMzY4NjgsMzM0MzQsMzM0MzcsMzQ4NTAsMzQ4NTIsMzQ4NTUsMzQ4NTYsMzczNzcsMzczNzgsMzczNzksMzczODAsMzczODEsMzczODIsMzczODMsMzczODQsMzczODUsMzczODYsMzczOTYsNDE0ODMsNDE0ODQsNDE0ODYsNDE0ODcsNDE0ODgsNDE0OTIsNDE0OTMsNDE0OTUsNDE3MjgsNDE3MjksNDE3MzAsNDE5ODUsNDE5ODYsNDE5ODcsNDE5ODgsNDE5ODksNDE5OTAsNDE5OTEsNDE5OTIsNDE5OTMsNDE5OTQsNDE5OTUsNDE5OTYsNDIwMTYsMCwyLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1LDE2LDE3LDE4LDIwLDIyLDIzLDI0LDI1LDI2LDI3LDI4LDMwOzgzQkQxRDlGMkU2OURFM0E4OTMwNUQ2QkM4Q0I1RkI5PC9leGlmOk5hdGl2ZURpZ2VzdD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAEgASADASIAAhEBAxEB/8QAHQAAAgMBAQEBAQAAAAAAAAAABQYDBAcIAgEACf/EAEQQAAIBAwMCBAUCBAMHAgQHAAECAwQFEQASIQYxEyJBUQcUMmFxI4EVQlKRCKGxFiQzYnLB0UPhCWOS8BclNESCsvH/xAAbAQACAwEBAQAAAAAAAAAAAAADBAIFBgEHAP/EADMRAAIBAwMCAwYGAwEBAQAAAAECAwAEEQUSITFBEyJRBjJhcZHwFIGhscHRFeHxI0Ki/9oADAMBAAIRAxEAPwDg+HpmsttZC1LJNUxywCc1m53jVCcHbxndnjbqxVGop6iCopoKWoqbbGEnjDFWi3knxAB3U5we2D316la/UlJT76uSveFg/MhWNSVyMDsOexxydCZquoWorrpSK1PVU9OMTRnDlmYLtyPqzk5Ht31kUPjPu61n0Ylv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') 0 0 no-repeat;
-}
+++ /dev/null
-body {
- width: 288px;
- height: 288px;
- background: transparent url('include/bob.jpg') 0 0 no-repeat;
-}
+++ /dev/null
-body {
- color: #ffffff;
-}
+++ /dev/null
-body {
- color: #ffffff;
-}
+++ /dev/null
-#header {
- background: #ffffff;
-}
+++ /dev/null
-body {
- color: #ffffff;
-}
+++ /dev/null
-#header {
- background: #ffffff;
-}
+++ /dev/null
-body {
- color: #ffffff;
-}
+++ /dev/null
-body {
- color: #ffffff;
-}
+++ /dev/null
-body {
- color: #ffffff;
-}
+++ /dev/null
-#header {
- background: #ffffff;
-}
+++ /dev/null
-.myRule {
- background-color: get-color(red);
- width: multiple-args(1px, 4px);
- background: string-result(3);
-}
+++ /dev/null
-body {
- width: 288px;
- height: 288px;
- background: transparent data-uri('include/bob.jpg') 0 0 no-repeat;
-}
+++ /dev/null
-@color: #ffffff;
+++ /dev/null
-@color: #ffffff;
+++ /dev/null
-@import "variables.less";
-body {
- color: @color;
-}
+++ /dev/null
-@import "include/variables.less";
-body {
- color: @color;
-}
+++ /dev/null
-@import "variables.less";
-body {
- color: @color;
-}
\ No newline at end of file
+++ /dev/null
-@import "variables.less";
-#header {
- background: @color;
-}
+++ /dev/null
-#footer {
- color: #377;
- background: #233;
-}
+++ /dev/null
-@import (less) "include/variablesAsLess.css";
-#header {
- background: @color;
-}
+++ /dev/null
-'use strict';
-
-var grunt = require('grunt');
-var fs = require('fs');
-
-exports.less = {
- compile: function(test) {
- test.expect(2);
-
- var actual = grunt.file.read('tmp/less.css');
- var expected = grunt.file.read('test/expected/less.css');
- test.equal(expected, actual, 'should compile less, with the ability to handle imported files from alternate include paths');
-
- actual = grunt.file.read('tmp/concat.css');
- expected = grunt.file.read('test/expected/concat.css');
- test.equal(expected, actual, 'should concat output when passed an array');
-
- test.done();
- },
- compress: function(test) {
- test.expect(1);
-
- var actual = grunt.file.read('tmp/compress.css');
- var expected = grunt.file.read('test/expected/compress.css');
- test.equal(expected, actual, 'should compress output when compress option is true');
-
- test.done();
- },
- nopaths: function(test) {
- test.expect(1);
-
- var actual = grunt.file.read('tmp/nopaths.css');
- var expected = grunt.file.read('test/expected/nopaths.css');
- test.equal(expected, actual, 'should default paths to the dirname of the less file');
-
- test.done();
- },
- cleancss: function(test) {
- test.expect(2);
-
- var actual = grunt.file.read('tmp/cleancss.css');
- var expected = grunt.file.read('test/expected/cleancss.css');
- test.equal(expected, actual, 'should cleancss output when cleancss option is true');
-
- actual = grunt.file.read('tmp/cleancssReport.css');
- expected = grunt.file.read('test/expected/cleancssReport.css');
- test.equal(expected, actual, 'should cleancss output when cleancss option is true and concating is enable');
-
- test.done();
- },
- ieCompat: function(test) {
- test.expect(2);
-
- var actual = grunt.file.read('tmp/ieCompatFalse.css');
- var expected = grunt.file.read('test/expected/ieCompatFalse.css');
- test.equal(expected, actual, 'should generate data-uris no matter the size when ieCompat option is true');
-
- actual = grunt.file.read('tmp/ieCompatTrue.css');
- expected = grunt.file.read('test/expected/ieCompatTrue.css');
- test.equal(expected, actual, 'should generate data-uris only when under the 32KB mark for Internet Explorer 8');
-
- test.done();
- },
- variablesAsLess: function(test) {
- test.expect(1);
-
- var actual = grunt.file.read('tmp/variablesAsLess.css');
- var expected = grunt.file.read('test/expected/variablesAsLess.css');
- test.equal(expected, actual, 'should process css files imported less files');
-
- test.done();
- },
- sourceMap: function(test) {
- test.expect(1);
-
- var actual = grunt.file.read('tmp/sourceMap.css');
- test.ok(actual.indexOf('/*# sourceMappingURL=') !== -1, 'compiled file should include a source map.');
-
- test.done();
- },
- sourceMapFilename: function(test) {
- test.expect(1);
-
- var sourceMap = grunt.file.readJSON('tmp/sourceMapFilename.css.map');
- test.equal(sourceMap.sources[0], 'test/fixtures/style3.less', 'should generate a sourceMap with the less file reference.');
-
- test.done();
- },
- sourceMapURL: function(test) {
- test.expect(1);
-
- var actual = grunt.file.read('tmp/sourceMapWithCustomURL.css');
- test.ok(actual.indexOf('/*# sourceMappingURL=custom/url/for/sourceMap.css.map') !== -1, 'compiled file should have a custom source map URL.');
- test.done();
- },
- sourceMapBasepath: function(test) {
- test.expect(1);
-
- var sourceMap = grunt.file.readJSON('tmp/sourceMapBasepath.css.map');
- test.equal(sourceMap.sources[0], 'style3.less', 'should use the basepath for the less file references in the generated sourceMap.');
-
- test.done();
- },
- sourceMapRootpath: function(test) {
- test.expect(1);
-
- var sourceMap = grunt.file.readJSON('tmp/sourceMapRootpath.css.map');
- test.equal(sourceMap.sources[0], 'http://example.org/test/fixtures/style3.less', 'should use the rootpath for the less file references in the generated sourceMap.');
-
- test.done();
- },
- sourceMapLessInline: function(test) {
- test.expect(1);
-
- var expected = grunt.file.read('test/fixtures/style3.less');
- var sourceMap = grunt.file.readJSON('tmp/sourceMapLessInline.css.map');
- test.equal(sourceMap.sourcesContent[0], expected, 'should put the less file into the generated sourceMap instead of referencing them.');
-
- test.done();
- },
- customFunctions: function(test) {
- test.expect(1);
-
- var actual = grunt.file.read('tmp/customFunctions.css');
- var expected = grunt.file.read('test/expected/customFunctions.css');
- test.equal(expected, actual, 'should execute custom functions');
-
- test.done();
- }
-};
+++ /dev/null
-{% extends "wiki/document_details_base.html" %}
-{% load i18n %}
-
-{% block extrabody %}
-{{ block.super }}
-<script src="{{ STATIC_URL }}js/lib/codemirror-0.8/codemirror.js" type="text/javascript" charset="utf-8">
-</script>
-<script src="{{ STATIC_URL }}js/wiki/loader.js" type="text/javascript" charset="utf-8"> </script>
-{% endblock %}
-
-{% block tabs-menu %}
- {% include "wiki/tabs/summary_view_item.html" %}
- {% include "wiki/tabs/wysiwyg_editor_item.html" %}
- {% include "wiki/tabs/source_editor_item.html" %}
- {% include "wiki/tabs/history_view_item.html" %}
-{% endblock %}
-
-{% block tabs-content %}
- {% include "wiki/tabs/summary_view.html" %}
- {% include "wiki/tabs/wysiwyg_editor.html" %}
- {% include "wiki/tabs/source_editor.html" %}
- {% include "wiki/tabs/history_view.html" %}
-{% endblock %}
-
-{% block tabs-right %}
- {% include "wiki/tabs/gallery_view_item.html" %}
- {% include "wiki/tabs/annotations_view_item.html" %}
- {% include "wiki/tabs/search_view_item.html" %}
-{% endblock %}
-
-{% block splitter-extra %}
-<div class="vsplitbar" title="{% trans "Click to open/close gallery" %}">
- <p class="vsplitbar-title"></p>
- </div>
- <div id="sidebar">
- {% include "wiki/tabs/gallery_view.html" %}
- {% include "wiki/tabs/annotations_view.html" %}
- {% include "wiki/tabs/search_view.html" %}
- </div>
-{% endblock %}
-
-{% block dialogs %}
- {% include "wiki/save_dialog.html" %}
- {% include "wiki/revert_dialog.html" %}
- {% include "wiki/tag_dialog.html" %}
- {% if can_pubmark %}
- {% include "wiki/pubmark_dialog.html" %}
- {% endif %}
-{% endblock %}
+++ /dev/null
-{% extends "base.html" %}
-{% load toolbar_tags i18n %}
-
-{% block title %}{{ book.title }} - {{ block.super }}{% endblock %}
-{% block extrahead %}
-{% load compressed %}
-{% compressed_css 'detail' %}
-{% endblock %}
-
-{% block extrabody %}
-<script type="text/javascript" charset="utf-8">
- var STATIC_URL = '{{STATIC_URL}}';
-</script>
-{% compressed_js 'detail' %}
-{% endblock %}
-
-{% block maincontent %}
-<div id="document-meta"
- data-chunk-id="{{ chunk.pk }}" style="display:none">
-
- <span data-key="gallery">{{ chunk.book.gallery }}</span>
- <span data-key="gallery-start">{% if chunk.gallery_start %}{{ chunk.gallery_start }}{% endif %}</span>
- <span data-key="revision">{{ revision }}</span>
- <span data-key="diff">{{ request.GET.diff }}</span>
-
- {% block meta-extra %} {% endblock %}
-</div>
-
-<div id="header">
- <h1><a href="{% url 'catalogue_document_list' %}"><img src="{{STATIC_URL}}icons/go-home.png"/><a href="{% url 'catalogue_document_list' %}">Strona<br>główna</a></h1>
- <div id="tools">
- <a href="{{ REDMINE_URL }}projects/wl-publikacje/wiki/Pomoc" target="_blank">
- {% trans "Help" %}</a>
- | {% include "registration/head_login.html" %}
- | {% trans "Version" %}: <span id="document-revision">{% trans "Unknown" %}</span>
- {% if not readonly %}
- | <button style="margin-left: 6px" id="save-button">{% trans "Save" %}</button>
- <span id='save-attempt-info'>{% trans "Save attempt in progress" %}</span>
- <span id='out-of-date-info'>{% trans "There is a newer version of this document!" %}</span>
- {% endif %}
- </div>
- <ol id="tabs" class="tabs">
- {% block tabs-menu %} {% endblock %}
- </ol>
- <ol id="tabs-right" class="tabs">
- {% block tabs-right %} {% endblock %}
- </ol>
-</div>
-<div id="splitter">
- <div id="editor" class="{% block editor-class %} {% endblock %}">
- {% block tabs-content %} {% endblock %}
- </div>
- {% block splitter-extra %} {% endblock %}
-</div>
-
-{% block dialogs %} {% endblock %}
-
-{% endblock %}
+++ /dev/null
-{% extends "wiki/document_details_base.html" %}
-{% load i18n %}
-
-{% block editor-class %}readonly{% endblock %}
-
-{% block extrabody %}
-{{ block.super }}
-<script src="{{STATIC_URL}}js/lib/codemirror-0.8/codemirror.js" type="text/javascript" charset="utf-8">
-</script>
-<script src="{{STATIC_URL}}js/wiki/loader_readonly.js" type="text/javascript" charset="utf-8"> </script>
-{% endblock %}
-
-{% block tabs-menu %}
- {% include "wiki/tabs/wysiwyg_editor_item.html" %}
- {% include "wiki/tabs/source_editor_item.html" %}
-{% endblock %}
-
-{% block tabs-content %}
- {% include "wiki/tabs/wysiwyg_editor.html" %}
- {% include "wiki/tabs/source_editor.html" %}
-{% endblock %}
-
-{% block splitter-extra %}
-{% endblock %}
-
-{% block dialogs %}
-{% endblock %}
\ No newline at end of file
+++ /dev/null
-{% load i18n %}
-<div id="history-view-editor" class="editor" style="display: none">
- <div class="toolbar">
- <button type="button" id="make-diff-button"
- data-enabled-when="2" disabled="disabled">{% trans "Compare versions" %}</button>
- {% if can_pubmark %}
- <button type="button" id="pubmark-changeset-button"
- data-enabled-when="1" disabled="disabled">{% trans "Mark for publishing" %}</button>
- {% endif %}
- <button type="button" id="doc-revert-button"
- data-enabled-when="1" disabled="disabled">{% trans "Revert document" %}</button>
- <button id="open-preview-button" disabled="disabled"
- data-enabled-when="1"
- data-basehref="{% url 'wiki_editor_readonly' chunk.book.slug chunk.slug %}">{% trans "View version" %}</button>
-
- </div>
- <div id="history-view">
- <p class="message-box" style="display:none;"></p>
-
- <table id="changes-list-container">
- <tbody id="changes-list">
- </tbody>
- <tbody style="display: none;">
- <tr class="entry row-stub">
- <td data-stub-value="version"></td>
- <td>
- <span data-stub-value="date"></span>
- <br/><span data-stub-value="author"></span>
- <br />
- <span data-stub-value="description"></span>
- </td>
- <td>
- <div data-stub-value="publishable"></div>
- <div data-stub-value="published"></div>
- <div data-stub-value="tag"></div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
-</div>
+++ /dev/null
-{% load i18n %}
-<li id="HistoryPerspective" data-ui-related="history-view-editor" data-ui-jsclass="HistoryPerspective">
- <span>{% trans "History" %}</span>
-</li>
+++ /dev/null
-{% load i18n %}
-<div id="summary-view-editor" class="editor" style="display: none">
- <!-- <div class="toolbar">
- </div> -->
- <div id="summary-view">
- <div class="summary-cover-area">
- <p><img id="summary-cover" class="book-cover"
- {% if revision %}
- src="{% url 'cover_preview' chunk.book.slug chunk.slug revision %}"
- {% else %}
- src="{% url 'cover_preview' chunk.book.slug chunk.slug %}"
- {% endif %}></p>
- <p><button id="summary-cover-refresh">{% trans "Refresh from working copy" %}</button></p>
- </div>
-
- <h2>
- <label for="title">{% trans "Title" %}:</label>
- <span data-ui-editable="true" data-edit-target="meta.displayTitle"
- >{{ chunk.pretty_name }}</span>
- </h2>
- <p><a href="{{ chunk.book.get_absolute_url }}">{% trans "Go to the book's page" %}</a>
- </p>
- <p>
- <label>{% trans "Document ID" %}:</label>
- <span>{{ chunk.book.slug }}/{{ chunk.slug }}</span>
- </p>
- <p>
- <label>{% trans "Current version" %}:</label>
- {{ chunk.revision }} ({{ chunk.head.created_at }})
- <p>
- <label>{% trans "Last edited by" %}:</label>
- {{ chunk.head.author }}
- </p>
- <p>
- <label for="gallery">{% trans "Link to gallery" %}:</label>
- <span data-ui-editable="true" data-edit-target="meta.galleryLink"
- >{{ chunk.book.gallery }}</span>
- </p>
- <p>
- <label>{% trans "Characters in document" %}:</label>
- <span id="charcount"></span> (<span id="charcount_pages"></span> {% trans "pages" %}<span id="charcount_untagged">, {% trans "untagged" %}</span>)
- </p>
- </div>
-</div>
+++ /dev/null
-{% load i18n %}
-<li id="SummaryPerspective" data-ui-related="summary-view-editor" data-ui-jsclass="SummaryPerspective">
- <span>{% trans "Summary" %}</span>
-</li>
from django.conf.urls import patterns, url
-urlpatterns = patterns('wiki.views',
+urlpatterns = patterns(
+ 'wiki.views',
url(r'^edit/(?P<pk>[^/]+)/$',
'editor', name="wiki_editor"),
- url(r'^readonly/(?P<pk>[^/]+)/$',
- 'editor_readonly', name="wiki_editor_readonly"),
-
url(r'^gallery/(?P<directory>[^/]+)/$',
'gallery', name="wiki_gallery"),
url(r'^history/(?P<doc_id>\d+)/$',
'history', name="wiki_history"),
- url(r'^rev/(?P<chunk_id>\d+)/$',
- 'revision', name="wiki_revision"),
-
url(r'^text/(?P<doc_id>\d+)/$',
'text', name="wiki_text"),
-from datetime import datetime
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
import json
import os
import logging
import urllib
from django.conf import settings
-from django.core.urlresolvers import reverse
from django import http
-from django.http import Http404, HttpResponseForbidden
+from django.http import HttpResponseForbidden
from django.middleware.gzip import GZipMiddleware
from django.utils.decorators import decorator_from_middleware
from django.utils.encoding import smart_unicode
from django.utils.formats import localize
from django.utils.translation import ugettext as _
-from django.views.decorators.http import require_POST, require_GET
+from django.views.decorators.http import require_POST
from django.shortcuts import get_object_or_404, render
-from django.contrib.auth.decorators import login_required
from catalogue.models import Document, Template
from dvcs.models import Revision
import nice_diff
from wiki import forms
-from wiki.helpers import (JSONResponse, JSONFormInvalid, JSONServerError,
- ajax_require_permission)
+from wiki.helpers import JSONResponse, JSONFormInvalid
#
# Quick hack around caching problems, TODO: use ETags
revisions = []
for i, revision in enumerate(document.history()):
revisions.append({
- "version": i + 1,
- "description": revision.description,
- "author": revision.author_str(),
- "date": localize(revision.created_at),
- "published": "",
- "revision": revision.pk,
- "published": _("Published") + ": " + \
- localize(revision.publish_log.order_by('-timestamp')[0].timestamp) \
- if revision.publish_log.exists() else "",
- })
+ "version": i + 1,
+ "description": revision.description,
+ "author": revision.author_str(),
+ "date": localize(revision.created_at),
+ "revision": revision.pk,
+ "published": _("Published") + ": " +
+ localize(revision.publish_log.order_by('-timestamp')[0].timestamp)
+ if revision.publish_log.exists() else "",
+ })
return revisions
@never_cache
-#@login_required
-def editor(request, pk, chunk=None, template_name='wiki/bootstrap.html'):
+def editor(request, pk, template_name='wiki/bootstrap.html'):
doc = get_object_or_404(Document, pk=pk, deleted=False)
- #~ if not doc.accessible(request):
- #~ return HttpResponseForbidden("Not authorized.")
-
- access_time = datetime.now()
save_form = forms.DocumentTextSaveForm(user=request.user, prefix="textsave")
- try:
- version = int(request.GET.get('version', None))
- except:
- version = None
- if version:
- text = doc.at_revision(version).materialize()
- else:
- text = doc.materialize()
- revision = doc.revision
+ text = doc.materialize()
+ revision = doc.revision
history = get_history(doc)
return render(request, template_name, {
'serialized_document_data': json.dumps({
'document_id': doc.pk,
'title': doc.meta().get('title', ''),
'history': history,
- 'version': len(history), #version or chunk.revision(),
+ 'version': len(history),
'revision': revision.pk,
'stage': doc.stage,
'assignment': str(doc.assigned_to),
})
-@require_GET
-def editor_readonly(request, slug, chunk=None, template_name='wiki/document_details_readonly.html'):
- try:
- chunk = Chunk.get(slug, chunk)
- revision = request.GET['revision']
- except (Chunk.MultipleObjectsReturned, Chunk.DoesNotExist, KeyError):
- raise Http404
- if not chunk.book.accessible(request):
- return HttpResponseForbidden("Not authorized.")
-
- access_time = datetime.now()
- last_books = request.session.get("wiki_last_books", {})
- last_books[slug, chunk.slug] = {
- 'time': access_time,
- 'title': chunk.book.title,
- }
-
- if len(last_books) > MAX_LAST_DOCS:
- oldest_key = min(last_books, key=lambda x: last_books[x]['time'])
- del last_books[oldest_key]
- request.session['wiki_last_books'] = last_books
-
- return render(request, template_name, {
- 'chunk': chunk,
- 'revision': revision,
- 'readonly': True,
- 'REDMINE_URL': settings.REDMINE_URL,
- })
-
-
@never_cache
@decorator_from_middleware(GZipMiddleware)
def text(request, doc_id):
doc = get_object_or_404(Document, pk=doc_id, deleted=False)
- #~ if not doc.book.accessible(request):
- #~ return HttpResponseForbidden("Not authorized.")
+ # if not doc.book.accessible(request):
+ # return HttpResponseForbidden("Not authorized.")
if request.method == 'POST':
form = forms.DocumentTextSaveForm(request.POST, user=request.user, prefix="textsave")
else:
author = None
text = form.cleaned_data['text']
- #~ parent_revision = form.cleaned_data['parent_revision']
- #~ if parent_revision is not None:
- #~ parent = doc.at_revision(parent_revision)
- #~ else:
- #~ parent = None
+ # parent_revision = form.cleaned_data['parent_revision']
+ # if parent_revision is not None:
+ # parent = doc.at_revision(parent_revision)
+ # else:
+ # parent = None
stage = form.cleaned_data['stage']
- #~ tags = [stage] if stage else []
- #~ publishable = (form.cleaned_data['publishable'] and
- #~ request.user.has_perm('catalogue.can_pubmark'))
+ # tags = [stage] if stage else []
+ # publishable = (form.cleaned_data['publishable'] and
+ # request.user.has_perm('catalogue.can_pubmark'))
try:
- doc.commit(author=author,
- text=text,
- parent=False,
- description=form.cleaned_data['comment'],
- author_name=form.cleaned_data['author_name'],
- author_email=form.cleaned_data['author_email'],
- )
+ doc.commit(
+ author=author,
+ text=text,
+ description=form.cleaned_data['comment'],
+ author_name=form.cleaned_data['author_name'],
+ author_email=form.cleaned_data['author_email'],
+ )
doc.set_stage(stage)
except:
from traceback import print_exc
print_exc()
raise
- #revision = doc.revision()
+ # revision = doc.revision()
return JSONResponse({
- 'text': None, #doc.materialize() if parent_revision != revision else None,
- #'version': revision,
- #'stage': doc.stage.name if doc.stage else None,
+ 'text': None, # doc.materialize() if parent_revision != revision else None,
+ # 'version': revision,
+ # 'stage': doc.stage.name if doc.stage else None,
'assignment': doc.assigned_to.username if doc.assigned_to else None
})
else:
else:
author = None
- #before = doc.revision
+ # before = doc.revision
logger.info("Reverting %s to %s", doc_id, rev.pk)
- doc.commit(author=author,
- text=rev.materialize(),
- parent=False, #?
- description=comment,
- #author_name=form.cleaned_data['author_name'], #?
- #author_email=form.cleaned_data['author_email'], #?
- )
+ doc.commit(
+ author=author,
+ text=rev.materialize(),
+ description=comment,
+ # author_name=form.cleaned_data['author_name'], #?
+ # author_email=form.cleaned_data['author_email'], #?
+ )
return JSONResponse({
- #'document': None, #doc.materialize() if before != doc.revision else None,
- #'version': doc.revision(),
+ # 'document': None, #doc.materialize() if before != doc.revision else None,
+ # 'version': doc.revision(),
})
else:
return JSONFormInvalid(form)
docA = ""
docB = Revision.objects.get(pk=revB).materialize()
- return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(),
- docB.splitlines(), context=3))
-
-
-@never_cache
-def revision(request, chunk_id):
- doc = get_object_or_404(Chunk, pk=chunk_id)
- if not doc.book.accessible(request):
- return HttpResponseForbidden("Not authorized.")
- return http.HttpResponse(str(doc.revision()))
+ return http.HttpResponse(nice_diff.html_diff_table(docA.splitlines(), docB.splitlines(), context=3))
@never_cache
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import with_statement
-import shutil
import os
import sys
import logging
+from string import Template
logging.basicConfig(stream=sys.stderr, format="%(levelname)s:: %(message)s", level=logging.INFO)
-from string import Template
class DeploySite(object):
site = cls(*args, **kwargs)
return site.deploy()
+
class WSGISite(DeploySite):
def __init__(self, **env):
if 'WSGI_FILE' not in self.env:
self.env['WSGI_FILE'] = os.path.join(self.env['ROOT'], 'www',
- 'wsgi', self.env['PROJECT_NAME']) + '.wsgi'
+ 'wsgi', self.env['PROJECT_NAME']) + '.wsgi'
self.env['WSGI_DIR'] = os.path.dirname(self.env['WSGI_FILE'])
source = self.find_resource(self.env['WSGI_SOURCE_FILE'])
self.render_template(source, self.env['WSGI_FILE'])
+
class PIPSite(DeploySite):
def install_dependencies(self):
except ValueError:
pass
+
class GitSite(DeploySite):
def update_app(self):
self.info("Updating repository.")
os.system("cd %s; git pull" % self.env['APP_DIR'])
+
class ApacheSite(DeploySite):
def __init__(self, **env):
-Subproject commit 25af49b6c63e1c005129856e107143864ad5b245
+Subproject commit d1037d617d8cd2cafc60e67ac0272f86d2e24dfa
# -*- coding: utf-8
+
def settings(request):
from django.conf import settings
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django import forms
+
class RegistrationForm(forms.Form):
first_name = forms.CharField()
last_name = forms.CharField()
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from __future__ import absolute_import
from os import path
from redakcja.settings.common import *
DATABASES = {
'default': {
- 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
- 'NAME': path.join(PROJECT_ROOT, 'dev.sqlite'), # Or path to database file if using sqlite3.
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': path.join(PROJECT_ROOT, 'dev.sqlite'),
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
}
}
-try:
- LOGGING_CONFIG_FILE
-except NameError:
- LOGGING_CONFIG_FILE = os.path.join(PROJECT_ROOT, 'config',
- ('logging.cfg' if not DEBUG else 'logging.cfg.dev'))
+LOGGING_CONFIG_FILE = os.path.join(PROJECT_ROOT, 'config', ('logging.cfg' if not DEBUG else 'logging.cfg.dev'))
try:
import logging
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en'
-#import locale
-#locale.setlocale(locale.LC_ALL, '')
+# import locale
+# locale.setlocale(locale.LC_ALL, '')
SITE_ID = 1
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
- "redakcja.context_processors.settings", # this is instead of media
+ "redakcja.context_processors.settings", # this is instead of media
'django.core.context_processors.csrf',
"django.core.context_processors.request",
)
'django.middleware.locale.LocaleMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
- #'django_cas.middleware.CASMiddleware',
+ # 'django_cas.middleware.CASMiddleware',
'django.contrib.admindocs.middleware.XViewMiddleware',
'pagination.middleware.PaginationMiddleware',
- #'maintenancemode.middleware.MaintenanceModeMiddleware',
+ # 'maintenancemode.middleware.MaintenanceModeMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)
-#AUTHENTICATION_BACKENDS = (
-# 'django.contrib.auth.backends.ModelBackend',
-# 'fnpdjango.auth_backends.AttrCASBackend',
-#)
+# AUTHENTICATION_BACKENDS = (
+# 'django.contrib.auth.backends.ModelBackend',
+# 'fnpdjango.auth_backends.AttrCASBackend',
+# )
ROOT_URLCONF = 'redakcja.urls'
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.flatpages',
- #'django.contrib.comments',
+ # 'django.contrib.comments',
- #'south',
+ # 'south',
'sorl.thumbnail',
'pagination',
- #'gravatar',
- #'kombu.transport.django',
+ # 'gravatar',
+ # 'kombu.transport.django',
'fileupload',
'pipeline',
'modeltranslation',
'catalogue',
- 'cover',
+ # 'cover',
'dvcs',
'organizations',
'wiki',
- #'toolbar',
- #'apiclient',
+ # 'toolbar',
+ # 'apiclient',
'email_mangler',
'build',
'attachments',
LOGIN_REDIRECT_URL = '/'
-#CAS_USER_ATTRS_MAP = {
-# 'email': 'email', 'firstname': 'first_name', 'lastname': 'last_name'}
+# CAS_USER_ATTRS_MAP = {
+# 'email': 'email', 'firstname': 'first_name', 'lastname': 'last_name'}
# REPOSITORY_PATH = '/Users/zuber/Projekty/platforma/files/books'
IMAGE_DIR = 'images/'
-#import djcelery
-#djcelery.setup_loader()
+# import djcelery
+# djcelery.setup_loader()
BROKER_BACKEND = "djkombu.transport.DatabaseTransport"
BROKER_HOST = "localhost"
FORMS_BUILDER_LABEL_MAX_LENGTH = 2048
-
try:
from redakcja.settings.compress import *
except ImportError:
pass
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
-# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+ # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
# CSS and JS files to compress
PIPELINE_CSS = {
'detail': {
- 'source_filenames': (
+ 'source_filenames': (
'css/master.css',
'css/toolbar.css',
'css/gallery.css',
},
'catalogue': {
'source_filenames': (
- #'css/filelist.css',
+ # 'css/filelist.css',
'css/base.css',
'datepicker/css/datepicker.css',
),
'output_filename': 'compressed/catalogue_styles.css',
- },
- 'book': {
+ },
+ 'book': {
'source_filenames': (
'css/book.css',
),
'datepicker/js/bootstrap-datepicker.js',
),
'output_filename': 'compressed/catalogue_scripts.js',
- },
- 'book': {
+ },
+ 'book': {
'source_filenames': (
'js/book_text/jquery.eventdelegation.js',
'js/book_text/jquery.scrollto.js',
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from redakcja.settings.test import *
NOSE_ARGS = ()
STATIC_ROOT_SYMLINK = os.path.dirname(STATIC_ROOT) + '_test'
STATICFILES_DIRS.append(STATIC_ROOT_SYMLINK)
-
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
#
# Nose tests
#
from redakcja.settings.common import *
+import tempfile
# ROOT_URLCONF = 'yourapp.settings.test.urls'
DATABASES = {
'default': {
- 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
- 'NAME': '', # Or path to database file if using sqlite3.
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': '', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
}
}
-import tempfile
CATALOGUE_REPO_PATH = tempfile.mkdtemp(prefix='redakcja-repo')
MEDIA_ROOT = tempfile.mkdtemp(prefix='media-root')
INSTALLED_APPS += ('django_nose', 'dvcs.tests')
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
-TEST_MODULES = ('catalogue', 'cover', 'dvcs.tests', 'wiki', 'toolbar')
-COVER_APPS = ('catalogue', 'cover', 'dvcs', 'wiki', 'toolbar')
+TEST_MODULES = ('catalogue', 'dvcs.tests', 'wiki', 'toolbar')
+COVER_APPS = ('catalogue', 'dvcs', 'wiki', 'toolbar')
NOSE_ARGS = (
'--tests=' + ','.join(TEST_MODULES),
'--cover-package=' + ','.join(COVER_APPS),
}
/* błędne wersy */
-.htmlview *:
-not(.strofa) > *[x-verse]::after {
+.htmlview *:not(.strofa) > *[x-verse]::after {
content: "Ten wers znajduje się poza strofą.";
display: inline;
background: red;
background-color: #ffcccc;
}
.htmlview .pe .annotation:hover {
- background-color: #96e0e4;*/
+ background-color: #96e0e4;
}
*.htmlview *.annotation-inline-box {
position: static;
+++ /dev/null
-if (!window.console) {
- window.console = {
- log: function(){
- }
- }
-}
-
-var DEFAULT_PERSPECTIVE = "#VisualPerspective";
-
-$(function()
-{
- var tabs = $('ol#tabs li');
- var gallery = null;
- CurrentDocument = new $.wikiapi.WikiDocument("document-meta");
-
- $.blockUI.defaults.baseZ = 10000;
-
- function initialize()
- {
- $(document).keydown(function(event) {
- console.log("Received key:", event);
- });
-
- /* The save button */
- $('#save-button').click(function(event){
- event.preventDefault();
- $.wiki.showDialog('#save_dialog');
- });
-
- $('.editor').hide();
-
- /*
- * TABS
- */
- $('.tabs li').live('click', function(event, callback) {
- $.wiki.switchToTab(this);
- });
-
- $('#tabs li > .tabclose').live('click', function(event, callback) {
- var $tab = $(this).parent();
-
- if($tab.is('.active'))
- $.wiki.switchToTab(DEFAULT_PERSPECTIVE);
-
- var p = $.wiki.perspectiveForTab($tab);
- p.destroy();
-
- return false;
- });
-
-
- $(window).resize(function(){
- $('iframe').height($(window).height() - $('#tabs').outerHeight() - $('#source-editor .toolbar').outerHeight());
- });
-
- $(window).resize();
-
- $('.vsplitbar').toggle(
- function() {
- $.wiki.state.perspectives.ScanGalleryPerspective.show = true;
- $('#sidebar').show();
- $('.vsplitbar').css('right', 480).addClass('active');
- $('#editor .editor').css('right', 510);
- $(window).resize();
- $.wiki.perspectiveForTab('#tabs-right .active').onEnter();
- },
- function() {
- var active_right = $.wiki.perspectiveForTab('#tabs-right .active');
- $.wiki.state.perspectives.ScanGalleryPerspective.show = false;
- $('#sidebar').hide();
- $('.vsplitbar').css('right', 0).removeClass('active');
- $(".vsplitbar-title").html("↑ " + active_right.vsplitbar + " ↑");
- $('#editor .editor').css('right', 30);
- $(window).resize();
- active_right.onExit();
- }
- );
-
- if($.wiki.state.perspectives.ScanGalleryPerspective.show){
- $('.vsplitbar').trigger('click');
- $(".vsplitbar-title").html("↓ GALERIA ↓");
- } else {
- $(".vsplitbar-title").html("↑ GALERIA ↑");
- }
- window.onbeforeunload = function(e) {
- if($.wiki.isDirty()) {
- e.returnValue = "Na stronie mogą być nie zapisane zmiany.";
- return "Na stronie mogą być nie zapisane zmiany.";
- };
- };
-
- console.log("Fetching document's text");
-
- $(document).bind('wlapi_document_changed', function(event, doc) {
- try {
- $('#document-revision').text(doc.revision);
- } catch(e) {
- console.log("Failed handler", e);
- }
- });
-
- CurrentDocument.fetch({
- success: function(){
- console.log("Fetch success");
- $('#loading-overlay').fadeOut();
- var active_tab = document.location.hash || DEFAULT_PERSPECTIVE;
-
- if(active_tab == "#ScanGalleryPerspective")
- active_tab = DEFAULT_PERSPECTIVE;
-
- console.log("Initial tab is:", active_tab)
- $.wiki.switchToTab(active_tab);
-
- /* every 5 minutes check for a newer version */
- var revTimer = setInterval(function() {
- CurrentDocument.checkRevision({outdated: function(){
- $('#header').addClass('out-of-date');
- clearInterval(revTimer);
- }});
- }, 300000);
- },
- failure: function() {
- $('#loading-overlay').fadeOut();
- alert("FAILURE");
- }
- });
- }; /* end of initialize() */
-
-
- /* Load configuration */
- $.wiki.loadConfig();
-
- var initAll = function(a, f) {
- if (a.length == 0) return f();
-
- $.wiki.initTab({
- tab: a.pop(),
- doc: CurrentDocument,
- callback: function(){
- initAll(a, f);
- }
- });
- };
-
-
- /*
- * Initialize all perspectives
- */
- initAll( $.makeArray($('.tabs li')), initialize);
- console.log(location.hash);
-});
});
old_callback.call(this);
- }
+ };
$.wiki.Perspective.call(this, options);
- };
+ }
SummaryPerspective.prototype = new $.wiki.Perspective();
(function($) {
- $.wikiapi = {};
- var noop = function() {
- };
- var noops = {
- success: noop,
- failure: noop
- };
- /*
- * Return absolute reverse path of given named view. (at least he have it
- * hard-coded in one place)
- *
- * TODO: think of a way, not to hard-code it here ;)
- *
- */
- function reverse() {
- var vname = arguments[0];
- var base_path = "/editor";
-
- if (vname == "ajax_document_text") {
- var path = "/text/" + arguments[1] + '/';
-
- if (arguments[2] !== undefined)
- path += arguments[2] + '/';
-
- return base_path + path;
- }
+ $.wikiapi = {};
+ var noop = function() {
+ };
+ var noops = {
+ success: noop,
+ failure: noop
+ };
+ /*
+ * Return absolute reverse path of given named view. (at least he have it
+ * hard-coded in one place)
+ *
+ * TODO: think of a way, not to hard-code it here ;)
+ *
+ */
+ function reverse() {
+ var vname = arguments[0];
+ var base_path = "/editor";
+
+ if (vname == "ajax_document_text") {
+ var path = "/text/" + arguments[1] + '/';
+
+ if (arguments[2] !== undefined)
+ path += arguments[2] + '/';
+
+ return base_path + path;
+ }
if (vname == "ajax_document_revert") {
return base_path + "/revert/" + arguments[1] + '/';
}
- if (vname == "ajax_document_history") {
+ if (vname == "ajax_document_history") {
- return base_path + "/history/" + arguments[1] + '/';
- }
+ return base_path + "/history/" + arguments[1] + '/';
+ }
- if (vname == "ajax_document_gallery") {
+ if (vname == "ajax_document_gallery") {
- return base_path + "/gallery/" + arguments[1] + '/';
- }
+ return base_path + "/gallery/" + arguments[1] + '/';
+ }
- if (vname == "ajax_document_diff")
- return base_path + "/diff/" + arguments[1] + '/';
+ if (vname == "ajax_document_diff")
+ return base_path + "/diff/" + arguments[1] + '/';
if (vname == "ajax_document_rev")
return base_path + "/rev/" + arguments[1] + '/';
- if (vname == "ajax_document_pubmark")
- return base_path + "/pubmark/" + arguments[1] + '/';
+ if (vname == "ajax_document_pubmark")
+ return base_path + "/pubmark/" + arguments[1] + '/';
- if (vname == "ajax_cover_preview")
- return "/cover/preview/";
+ if (vname == "ajax_cover_preview")
+ return "/cover/preview/";
- console.log("Couldn't reverse match:", vname);
- return "/404.html";
- };
+ console.log("Couldn't reverse match:", vname);
+ return "/404.html";
+ }
- /*
- * Document Abstraction
- */
- function WikiDocument(element_id) {
- var meta = $('#' + element_id);
- this.id = meta.attr('data-chunk-id');
+ /*
+ * Document Abstraction
+ */
+ function WikiDocument(element_id) {
+ var meta = $('#' + element_id);
+ this.id = meta.attr('data-chunk-id');
- this.revision = $("*[data-key='revision']", meta).text();
- this.readonly = !!$("*[data-key='readonly']", meta).text();
+ this.revision = $("*[data-key='revision']", meta).text();
+ this.readonly = !!$("*[data-key='readonly']", meta).text();
- this.galleryLink = $("*[data-key='gallery']", meta).text();
+ this.galleryLink = $("*[data-key='gallery']", meta).text();
this.galleryStart = parseInt($("*[data-key='gallery-start']", meta).text());
var diff = $("*[data-key='diff']", meta).text();
this.diff = diff;
else if (diff.length == 1) {
diff = parseInt(diff);
- if (diff != NaN)
+ if (!isNaN(diff))
this.diff = [diff - 1, diff];
}
}
- this.galleryImages = [];
- this.text = null;
- this.has_local_changes = false;
- this._lock = -1;
- this._context_lock = -1;
- this._lock_count = 0;
- };
-
- WikiDocument.prototype.triggerDocumentChanged = function() {
- $(document).trigger('wlapi_document_changed', this);
- };
- /*
- * Fetch text of this document.
- */
- WikiDocument.prototype.fetch = function(params) {
- params = $.extend({}, noops, params);
- var self = this;
- $.ajax({
- method: "GET",
- url: reverse("ajax_document_text", self.id),
- data: {"revision": self.revision},
- dataType: 'json',
- success: function(data) {
- var changed = false;
-
- if (self.text === null || self.revision !== data.revision) {
- self.text = data.text;
- self.revision = data.revision;
- self.gallery = data.gallery;
- changed = true;
- self.triggerDocumentChanged();
- };
-
- self.has_local_changes = false;
- params['success'](self, changed);
- },
- error: function() {
- params['failure'](self, "Nie udało się wczytać treści dokumentu.");
- }
- });
- };
- /*
- * Fetch history of this document.
- *
- * from - First revision to fetch (default = 0) upto - Last revision to
- * fetch (default = tip)
- *
- */
- WikiDocument.prototype.fetchHistory = function(params) {
- /* this doesn't modify anything, so no locks */
- params = $.extend({}, noops, params);
- var self = this;
- $.ajax({
- method: "GET",
- url: reverse("ajax_document_history", self.id),
- dataType: 'json',
- data: {
- "from": params['from'],
- "upto": params['upto']
- },
- success: function(data) {
- params['success'](self, data);
- },
- error: function() {
- params['failure'](self, "Nie udało się wczytać historii dokumentu.");
- }
- });
- };
- WikiDocument.prototype.fetchDiff = function(params) {
- /* this doesn't modify anything, so no locks */
- var self = this;
- params = $.extend({
- 'from': self.revision,
- 'to': self.revision
- }, noops, params);
- $.ajax({
- method: "GET",
- url: reverse("ajax_document_diff", self.id),
- dataType: 'html',
- data: {
- "from": params['from'],
- "to": params['to']
- },
- success: function(data) {
- params['success'](self, data);
- },
- error: function() {
- params['failure'](self, "Nie udało się wczytać porównania wersji.");
- }
- });
- };
-
- WikiDocument.prototype.checkRevision = function(params) {
- /* this doesn't modify anything, so no locks */
+ this.galleryImages = [];
+ this.text = null;
+ this.has_local_changes = false;
+ this._lock = -1;
+ this._context_lock = -1;
+ this._lock_count = 0;
+ }
+
+ WikiDocument.prototype.triggerDocumentChanged = function() {
+ $(document).trigger('wlapi_document_changed', this);
+ };
+ /*
+ * Fetch text of this document.
+ */
+ WikiDocument.prototype.fetch = function(params) {
+ params = $.extend({}, noops, params);
var self = this;
$.ajax({
method: "GET",
- url: reverse("ajax_document_rev", self.id),
- dataType: 'text',
+ url: reverse("ajax_document_text", self.id),
+ data: {"revision": self.revision},
+ dataType: 'json',
success: function(data) {
- if (data == '') {
- if (params.error)
- params.error();
+ var changed = false;
+
+ if (self.text === null || self.revision !== data.revision) {
+ self.text = data.text;
+ self.revision = data.revision;
+ self.gallery = data.gallery;
+ changed = true;
+ self.triggerDocumentChanged();
}
- else if (data != self.revision)
- params.outdated();
+
+ self.has_local_changes = false;
+ params['success'](self, changed);
+ },
+ error: function() {
+ params['failure'](self, "Nie udało się wczytać treści dokumentu.");
+ }
+ });
+ };
+ /*
+ * Fetch history of this document.
+ *
+ * from - First revision to fetch (default = 0) upto - Last revision to
+ * fetch (default = tip)
+ *
+ */
+ WikiDocument.prototype.fetchHistory = function(params) {
+ /* this doesn't modify anything, so no locks */
+ params = $.extend({}, noops, params);
+ var self = this;
+ $.ajax({
+ method: "GET",
+ url: reverse("ajax_document_history", self.id),
+ dataType: 'json',
+ data: {
+ "from": params['from'],
+ "upto": params['upto']
+ },
+ success: function(data) {
+ params['success'](self, data);
+ },
+ error: function() {
+ params['failure'](self, "Nie udało się wczytać historii dokumentu.");
+ }
+ });
+ };
+ WikiDocument.prototype.fetchDiff = function(params) {
+ /* this doesn't modify anything, so no locks */
+ var self = this;
+ params = $.extend({
+ 'from': self.revision,
+ 'to': self.revision
+ }, noops, params);
+ $.ajax({
+ method: "GET",
+ url: reverse("ajax_document_diff", self.id),
+ dataType: 'html',
+ data: {
+ "from": params['from'],
+ "to": params['to']
+ },
+ success: function(data) {
+ params['success'](self, data);
+ },
+ error: function() {
+ params['failure'](self, "Nie udało się wczytać porównania wersji.");
}
});
};
- /*
- * Fetch gallery
- */
- WikiDocument.prototype.refreshGallery = function(params) {
- params = $.extend({}, noops, params);
- var self = this;
- $.ajax({
- method: "GET",
- url: reverse("ajax_document_gallery", self.galleryLink),
- dataType: 'json',
- // data: {},
- success: function(data) {
- self.galleryImages = data;
- params['success'](self, data);
- },
- error: function(xhr) {
+ /*
+ * Fetch gallery
+ */
+ WikiDocument.prototype.refreshGallery = function(params) {
+ params = $.extend({}, noops, params);
+ var self = this;
+ $.ajax({
+ method: "GET",
+ url: reverse("ajax_document_gallery", self.galleryLink),
+ dataType: 'json',
+ // data: {},
+ success: function(data) {
+ self.galleryImages = data;
+ params['success'](self, data);
+ },
+ error: function(xhr) {
+ var msg;
switch (xhr.status) {
case 403:
- var msg = 'Galerie dostępne tylko dla zalogowanych użytkowników.';
+ msg = 'Galerie dostępne tylko dla zalogowanych użytkowników.';
break;
case 404:
- var msg = "Nie znaleziono galerii o nazwie: '" + self.galleryLink + "'.";
+ msg = "Nie znaleziono galerii o nazwie: '" + self.galleryLink + "'.";
+ break;
default:
- var msg = "Nie udało się wczytać galerii o nazwie: '" + self.galleryLink + "'.";
+ msg = "Nie udało się wczytać galerii o nazwie: '" + self.galleryLink + "'.";
}
- self.galleryImages = [];
- params['failure'](self, "<p>" + msg + "</p>");
- }
- });
- };
-
- /*
- * Set document's text
- */
- WikiDocument.prototype.setText = function(text) {
- this.text = text;
- this.has_local_changes = true;
- };
-
- /*
- * Set document's gallery link
- */
- WikiDocument.prototype.setGalleryLink = function(gallery) {
- this.galleryLink = gallery;
- this.has_local_changes = true;
- };
-
- /*
- * Save text back to the server
- */
- WikiDocument.prototype.save = function(params) {
- params = $.extend({}, noops, params);
- var self = this;
-
- if (!self.has_local_changes) {
- console.log("Abort: no changes.");
- return params['success'](self, false, "Nie ma zmian do zapisania.");
- };
-
- // Serialize form to dictionary
- var data = {};
- $.each(params['form'].serializeArray(), function() {
- data[this.name] = this.value;
- });
-
- data['textsave-text'] = self.text;
-
- $.ajax({
- url: reverse("ajax_document_text", self.id),
- type: "POST",
- dataType: "json",
- data: data,
- success: function(data) {
- var changed = false;
+ self.galleryImages = [];
+ params['failure'](self, "<p>" + msg + "</p>");
+ }
+ });
+ };
+
+ /*
+ * Set document's text
+ */
+ WikiDocument.prototype.setText = function(text) {
+ this.text = text;
+ this.has_local_changes = true;
+ };
+
+ /*
+ * Set document's gallery link
+ */
+ WikiDocument.prototype.setGalleryLink = function(gallery) {
+ this.galleryLink = gallery;
+ this.has_local_changes = true;
+ };
+
+ /*
+ * Save text back to the server
+ */
+ WikiDocument.prototype.save = function(params) {
+ params = $.extend({}, noops, params);
+ var self = this;
+
+ if (!self.has_local_changes) {
+ console.log("Abort: no changes.");
+ return params['success'](self, false, "Nie ma zmian do zapisania.");
+ }
+
+ // Serialize form to dictionary
+ var data = {};
+ $.each(params['form'].serializeArray(), function() {
+ data[this.name] = this.value;
+ });
+
+ data['textsave-text'] = self.text;
+
+ $.ajax({
+ url: reverse("ajax_document_text", self.id),
+ type: "POST",
+ dataType: "json",
+ data: data,
+ success: function(data) {
+ var changed = false;
$('#header').removeClass('saving');
- if (data.text) {
- self.text = data.text;
- self.revision = data.revision;
- self.gallery = data.gallery;
- changed = true;
- self.triggerDocumentChanged();
- };
-
- params['success'](self, changed, ((changed && "Udało się zapisać :)") || "Twoja wersja i serwera jest identyczna"));
- },
- error: function(xhr) {
+ if (data.text) {
+ self.text = data.text;
+ self.revision = data.revision;
+ self.gallery = data.gallery;
+ changed = true;
+ self.triggerDocumentChanged();
+ }
+
+ params['success'](self, changed, ((changed && "Udało się zapisać :)") || "Twoja wersja i serwera jest identyczna"));
+ },
+ error: function(xhr) {
if ($('#header').hasClass('saving')) {
$('#header').removeClass('saving');
$.blockUI({
params['failure'](self, {
"__message": "<p>Nie udało się zapisać - błąd serwera.</p>"
});
- };
+ }
}
- }
- });
+ }
+ });
$('#save-hide').click(function(){
$('#header').addClass('saving');
$.unblockUI();
$.wiki.blocking.unblock();
});
- }; /* end of save() */
+ }; /* end of save() */
WikiDocument.prototype.revertToVersion = function(params) {
var self = this;
});
};
- WikiDocument.prototype.pubmark = function(params) {
- params = $.extend({}, noops, params);
- var self = this;
- var data = {
- "pubmark-id": self.id,
- };
-
- /* unpack form */
- $.each(params.form.serializeArray(), function() {
- data[this.name] = this.value;
- });
-
- $.ajax({
- url: reverse("ajax_document_pubmark", self.id),
- type: "POST",
- dataType: "json",
- data: data,
- success: function(data) {
- params.success(self, data.message);
- },
- error: function(xhr) {
- if (xhr.status == 403 || xhr.status == 401) {
- params.failure(self, {
- "__all__": ["Nie masz uprawnień lub nie jesteś zalogowany."]
- });
- }
- else {
- try {
- params.failure(self, $.parseJSON(xhr.responseText));
- }
- catch (e) {
- params.failure(self, {
- "__all__": ["Nie udało się - błąd serwera."]
- });
- };
- };
- }
- });
- };
-
- WikiDocument.prototype.refreshCover = function(params) {
+ WikiDocument.prototype.pubmark = function(params) {
+ params = $.extend({}, noops, params);
var self = this;
- var data = {
- xml: self.text // TODO: send just DC
- };
+ var data = {
+ "pubmark-id": self.id
+ };
+
+ /* unpack form */
+ $.each(params.form.serializeArray(), function() {
+ data[this.name] = this.value;
+ });
+
+ $.ajax({
+ url: reverse("ajax_document_pubmark", self.id),
+ type: "POST",
+ dataType: "json",
+ data: data,
+ success: function(data) {
+ params.success(self, data.message);
+ },
+ error: function(xhr) {
+ if (xhr.status == 403 || xhr.status == 401) {
+ params.failure(self, {
+ "__all__": ["Nie masz uprawnień lub nie jesteś zalogowany."]
+ });
+ }
+ else {
+ try {
+ params.failure(self, $.parseJSON(xhr.responseText));
+ }
+ catch (e) {
+ params.failure(self, {
+ "__all__": ["Nie udało się - błąd serwera."]
+ });
+ }
+ }
+ }
+ });
+ };
+
+ /* unused except view_summary.js which is apparently unused */
+ WikiDocument.prototype.refreshCover = function(params) {
+ var self = this;
+ var data = {
+ xml: self.text // TODO: send just DC
+ };
$.ajax({
url: reverse("ajax_cover_preview"),
type: "POST",
// params.failure("Nie udało się odświeżyć okładki - błąd serwera.");
}
});
- };
+ };
WikiDocument.prototype.getLength = function(params) {
var text = $(doc).text();
text = $.trim(text.replace(/\s{2,}/g, ' '));
return text.length;
- }
+ };
- $.wikiapi.WikiDocument = WikiDocument;
+ $.wikiapi.WikiDocument = WikiDocument;
})(jQuery);
{% endif %}
<li><a href="{% url 'logout' %}">{% trans "Logout" %}</a></li>
</ul>
- </div>
</li>
>
{% trans "Log in / Register" %}
</button>
- <div class="dropdown-menu" style="padding:0;margin-top:-5px; border:none;box-shadow:none; min-width:240px">
- <div class="panel panel-default" style="color: #333;">
+ <div class="dropdown-menu" style="padding:0;margin-top:-5px; border:none;box-shadow:none; min-width:240px">
+ <div class="panel panel-default" style="color: #333;">
<div class="panel-heading">
<h3 class="panel-title">{% trans "Log in / Register" %}</h3>
</div>
<p style="margin-bottom:1em">{% trans "<strong>Register now</strong> to start editing your own materials." %}</p>
<a class="btn btn-default" href="{% url 'register' %}">{% trans "Register" %}</a>
</div>
+ </div>
</div>
</li>
{% endifnotequal %}
from django.conf import settings
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
-from django.views.generic import RedirectView
import forms_builder.forms.urls
admin.autodiscover()
-urlpatterns = patterns('',
+urlpatterns = patterns(
+ '',
# Auth
- #url(r'^accounts/login/$', 'django_cas.views.login', name='login'),
- #url(r'^accounts/logout/$', 'django_cas.views.logout', name='logout'),
- #url(r'^accounts/login/$', 'django.contrib.auth.views.login', name='login'),
- #url(r'^accounts/logout/$', 'django.contrib.auth.views.login', name='logout'),
- #url(r'^admin/login/$', 'django_cas.views.login', name='login'),
- #url(r'^admin/logout/$', 'django_cas.views.logout', name='logout'),
+ # url(r'^accounts/login/$', 'django_cas.views.login', name='login'),
+ # url(r'^accounts/logout/$', 'django_cas.views.logout', name='logout'),
+ # url(r'^accounts/login/$', 'django.contrib.auth.views.login', name='login'),
+ # url(r'^accounts/logout/$', 'django.contrib.auth.views.login', name='logout'),
+ # url(r'^admin/login/$', 'django_cas.views.login', name='login'),
+ # url(r'^admin/logout/$', 'django_cas.views.logout', name='logout'),
url('^accounts/', include('django.contrib.auth.urls')),
# Admin panel
url(r'^register$', 'redakcja.views.register', name='register'),
url(r'^documents/', include('catalogue.urls')),
url(r'^editor/', include('wiki.urls')),
- url(r'^cover/', include('cover.urls')),
url(r'^organizations/', include('organizations.urls')),
url(r'^forms/', include(forms_builder.forms.urls)),
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
if getattr(settings, 'SERVE_FILES_WITH_DEBUG_FALSE', False):
- urlpatterns += patterns('',
- (r'^%s(?P<path>.*)$' % settings.STATIC_URL[1:], 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
- (r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:], 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
-)
+ urlpatterns += patterns(
+ '',
+ (r'^%s(?P<path>.*)$' % settings.STATIC_URL[1:],
+ 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),
+ (r'^%s(?P<path>.*)$' % settings.MEDIA_URL[1:],
+ 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
+ )
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from catalogue.models import Document
from organizations.models import Organization
+
def main(request):
upcoming = Document.objects.filter(deleted=False).filter(publish_log=None)
finished = Document.objects.filter(deleted=False).exclude(publish_log=None)
finished = finished[:8]
organizations = organizations[:8]
-
return render(request, 'main.html', {
'finished': finished,
'upcoming': upcoming,
'more_organizations': more_organizations,
})
+
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST, request.FILES)
u.set_password(form.cleaned_data['password'])
u.save()
login(request, authenticate(username=form.cleaned_data['email'], password=form.cleaned_data['password']))
- send_mail('Registered at MIL/PEER',
-'''You have been successfully registered at MIL/PEER with this e-mail address.
+ send_mail(
+ 'Registered at MIL/PEER',
+ '''You have been successfully registered at MIL/PEER with this e-mail address.
Thank you.
-import os
+# -*- coding: utf-8 -*-
+#
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
import os.path
import sys
+# -*- coding: utf-8 -*-\r
+#\r
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.\r
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.\r
+#\r
import os\r
from django.conf import settings\r
\r
if not os.path.exists(settings.STATIC_ROOT_SYMLINK):\r
- os.symlink(settings.STATIC_ROOT, settings.STATIC_ROOT_SYMLINK)
\ No newline at end of file
+ os.symlink(settings.STATIC_ROOT, settings.STATIC_ROOT_SYMLINK)\r
+# -*- coding: utf-8 -*-\r
+#\r
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.\r
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.\r
+#\r
import os\r
import inspect\r
-from urlparse import urlparse\r
\r
from django.test import LiveServerTestCase\r
from django.test.client import Client\r
from django.conf import settings\r
-from django.contrib.auth.models import User, Permission\r
+from django.contrib.auth.models import User\r
from django.utils.translation import ugettext as _\r
\r
-from selenium import webdriver, selenium\r
-from selenium.webdriver.support.wait import WebDriverWait\r
+from selenium import webdriver\r
\r
\r
class SeleniumTestCase(LiveServerTestCase):\r
def setUp(self):\r
self.browser.delete_all_cookies()\r
\r
- def create_user(self, username = 'testuser', passwd = 'passwd', do_login = False):\r
+ def create_user(self, username='testuser', passwd='passwd', do_login=False):\r
user = User.objects.create_user(username, '', passwd)\r
user._plain_passwd = passwd\r
if do_login:\r
\r
def login_user(self, user):\r
client = Client()\r
- client.login(username = user.username, password = user._plain_passwd)\r
+ client.login(username=user.username, password=user._plain_passwd)\r
\r
if not self.browser.current_url.startswith(self.live_server_url):\r
self.browser.get(self.live_server_url+'/not_existing_url')\r
\r
- self.browser.find_element_by_tag_name('body') # Make sure the page is actually loaded before setting the cookie\r
+ self.browser.find_element_by_tag_name('body') # Make sure the page is actually loaded before setting the cookie\r
self.browser.delete_cookie(settings.SESSION_COOKIE_NAME)\r
- self.browser.add_cookie(dict(name = settings.SESSION_COOKIE_NAME, \r
- value = client.cookies[settings.SESSION_COOKIE_NAME].value,\r
- path = '/')\r
- )\r
+ self.browser.add_cookie(dict(name=settings.SESSION_COOKIE_NAME,\r
+ value=client.cookies[settings.SESSION_COOKIE_NAME].value,\r
+ path='/'))\r
\r
def get_main_page(self):\r
self.browser.get(self.live_server_url)\r
a.click()\r
self.tab = find_tab_class(tab_title)(self.browser)\r
return\r
- raise Exception, 'Tab not found'\r
+ raise Exception('Tab not found')\r
\r
\r
def find_tab_class(tab_title): \r
@property\r
def visible_books_count(self):\r
return len(self.element.find_element_by_id('file-list').find_elements_by_tag_name('tr')) - 2\r
- \r
-
\ No newline at end of file
-from tests.integration.base import SeleniumTestCase, MainPage, _\r
+# -*- coding: utf-8 -*-\r
+#\r
+# This file is part of MIL/PEER, licensed under GNU Affero GPLv3 or later.\r
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.\r
+#\r
+from tests.integration.base import SeleniumTestCase\r
+from django.utils.translation import ugettext as _\r
+\r
\r
class SmokeTest(SeleniumTestCase):\r
\r
def test_add_book(self):\r
- user = self.create_super_user(do_login = True)\r
- \r
page = self.get_main_page()\r
page.select_tab(_('All'))\r
assert page.tab.visible_books_count == 0\r
page.tab.submit()\r
page.select_tab(_('All'))\r
assert page.tab.visible_books_count == 1\r
-
\ No newline at end of file