diff --git a/app/controllers/Videos.java b/app/controllers/Videos.java new file mode 100644 index 0000000..1985416 --- /dev/null +++ b/app/controllers/Videos.java @@ -0,0 +1,263 @@ +package controllers; + +import java.io.*; +import play.*; +import play.data.validation.Error; +import play.libs.*; +import play.libs.WS.*; +import play.mvc.*; +import play.db.jpa.*; +import models.*; + +import java.util.*; +import java.util.regex.*; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; + +import java.io.IOException; + +import java.nio.charset.Charset; +import java.io.Reader; +import java.net.URL; +import java.net.MalformedURLException; + +import com.google.gson.*; + + +@With(Secure.class) +public class Videos extends OBController { + + + public static void listLinkedVideos(long ownerId){ + User user = User.findById(ownerId); + List videos = LinkedVideo.find("owner = ? order by createdAt asc", user).fetch(); + render(videos); + } + + public static void listMyLinkedVideos(){ + User user = user(); + + if(user == null) + forbidden(); + + List videos = LinkedVideo.find("owner = ? order by createdAt asc", user).fetch(); + renderTemplate("Videos/listLinkedVideos.html", videos); + } + + public static void showLinkedVideo(Long linkedVideoID){ + LinkedVideo vid = LinkedVideo.findById(linkedVideoID); + render(vid); + } + + public static void createLinkedVideo(String video_title, String video_link, String video_caption){ + validation.required(video_title).message("Video title is required"); + validation.required(video_link).message("Link must not be blank"); + validation.url(video_link).message("Link must be a valid URL (ex. http://www.example.com)"); + + char link_type = decipherLinkType(video_link); + validation.isTrue(link_type != '\u0000').message("Link must be a valid vimeo, youtube or dailymotion video link."); + + Logger.info("A log message: " + link_type); + validation.isTrue(isValidVideo(video_link)).message("Link must be a valid video"); + + User usr = user(); + + if(validation.hasErrors()){ + renderTemplate("Videos/listLinkedVideos.html"); + } + else{ + + LinkedVideo new_vid = new LinkedVideo(usr, video_title, video_link, video_caption, (int)link_type, getVideoId(video_link, link_type)); + + // + // new_vid.thoseWhoLike = new HashSet(); + // new_vid.comments = new ArrayList(); + + new_vid.thumbnail_url = getThumb(new_vid.video_id, link_type); + + new_vid.save(); + + showLinkedVideo(new_vid.id); + } + + } + + + public static void uploadVideo(){ + + } + + public static void createUploadedVideo(){ + + } + + public static char decipherLinkType(String link){ + + Pattern YOUTUBE = Pattern.compile("(?:https?://)?(?:www\\.)?(?:youtu\\.be/|youtube\\.com\\S*[^\\w\\-\\s])([\\w\\-]{11})(?=[^\\w\\-]|$)[?=&+%\\w\\-]*"); + Pattern DAILYMOTION = Pattern.compile("(?:https?://)?(?:www\\.)?dailymotion\\.com/video/([\\w\\d]{6})(?:_.*)?"); + Pattern VIMEO = Pattern.compile("(?:https?://)?(?:www\\.)?vimeo\\.com/([\\d]+)"); + + Matcher y = YOUTUBE.matcher(link); + Matcher d = DAILYMOTION.matcher(link); + Matcher v = VIMEO.matcher(link); + + if (y.matches()) + return 'y'; + else if(d.matches()) + return 'd'; + else if(v.matches()) + return 'v'; + else + return '\u0000'; + + } + + public static String getVideoId(String link, char link_type){ + + Pattern YOUTUBE = Pattern.compile("https?://(?:www\\.)?(?:youtu\\.be/|youtube\\.com\\S*[^\\w\\-\\s])([\\w\\-]{11})(?=[^\\w\\-]|$)[?=&+%\\w\\-]*"); + Pattern DAILYMOTION = Pattern.compile("https?://(?:www\\.)?dailymotion\\.com/video/([\\w\\d]{6})(?:_.*)?"); + Pattern VIMEO = Pattern.compile("https?://(?:www\\.)?vimeo\\.com/([\\d]+)"); + + Matcher m; + String videoId = ""; + if(link_type == 'y'){ + m = YOUTUBE.matcher(link); + if(m.find()){ + videoId = m.group(1); + } + } + else if(link_type == 'd'){ + m = DAILYMOTION.matcher(link); + if(m.find()){ + videoId = m.group(1); + } + } + else if(link_type == 'v'){ + m = VIMEO.matcher(link); + if(m.find()){ + videoId = m.group(1); + Logger.info("MGROUP: " + m.group(1)); + } + } + + return videoId; + } + + public static String getThumb(String video_id, char link_type){ + + if(link_type == 'y'){ + return "http://img.youtube.com/vi/" + video_id + "/1.jpg"; + } + else if(link_type =='d'){ + return "http://www.dailymotion.com/thumbnail/160x120/video/" + video_id + "/"; + } + else if(link_type =='v'){ + String info_url = "http://www.vimeo.com/api/v2/video/" + video_id + ".json"; + String json_text = jsonStringFromUrl(info_url); + + Logger.info("JSON TEXT: " + json_text); + + JsonParser parser = new JsonParser(); + + JsonArray json_array = (JsonArray)parser.parse(json_text); + JsonElement json_element = json_array.get(0); + + JsonObject json_object = (JsonObject)parser.parse(json_element.toString()); + + + return json_object.get("thumbnail_small").getAsString(); + + } + + return "blah"; + } + + public static String jsonStringFromUrl (String url){ + + String json_text = ""; + try{ + URL json_url = new URL(url); + + Logger.info("URL: " + url); + + InputStream inputstream = json_url.openStream(); + InputStreamReader is_reader = new InputStreamReader(inputstream, Charset.forName("UTF-8")); + BufferedReader b_reader = new BufferedReader(is_reader); + + json_text = readerToString(b_reader); + + } catch (MalformedURLException e){ + e.printStackTrace(); + } catch (IOException e){ + e.printStackTrace(); + } + + + return json_text; + } + + private static String readerToString(Reader reader) { + StringBuilder builder = new StringBuilder(); + + try{ + int i = 0; + while ((i = reader.read()) != -1) { + builder.append((char) i); + } + } catch (IOException e){ + e.printStackTrace(); + } + + return builder.toString(); + } + + private static boolean isValidVideo(String link){ + WS web_serv = new WS(); + WS.WSRequest ws_request = web_serv.url(link); + WS.HttpResponse response = ws_request.get(); + + if(response.getStatus() == 200 || response.getStatus() == 301) + return true; + else + return false; + } + + public static void addComment(long vid_id, String comment){ + LinkedVideo vid = LinkedVideo.findById(vid_id); + vid.addComment(user(), comment); + + showLinkedVideo(vid_id); + } + + public static void removeComment(long comment_id){ + Comment com = Comment.findById(comment_id); + LinkedVideo vid = (LinkedVideo) com.parentObj; + if (!com.owner.equals(user())) + forbidden(); + com.delete(); + + showLinkedVideo(vid.id); + + } + + public static void removeLinkedVideo(long video_id){ + LinkedVideo vid = LinkedVideo.findById(video_id); + User owner = vid.owner; + if (!owner.equals(user())) + forbidden(); + List comments = vid.comments(); + + for(int i = 0; i < comments.size(); i++){ + Comment comment = comments.remove(i); + comment.delete(); + } + vid.delete(); + + listLinkedVideos(owner.id); + } + + + +} diff --git a/app/models/LinkedVideo.java b/app/models/LinkedVideo.java new file mode 100644 index 0000000..1898e81 --- /dev/null +++ b/app/models/LinkedVideo.java @@ -0,0 +1,77 @@ +package models; + +import java.util.*; +import javax.persistence.*; +import play.db.jpa.*; +import play.data.validation.*; +import java.util.regex.*; + +@Entity +public class LinkedVideo extends Post { + + @Required + @URL public String link; + + public int link_type; + public String video_id; + + public String thumbnail_url; + + @Required + public String title; + + public String caption; + + @Required + @ManyToOne + @JoinTable(name="LinkedVideoToUser") + public User owner; + + + public LinkedVideo(User owner, String title, String link, String caption, int link_type, String video_id){ + super(owner, owner, ""); + this.title = title; + this.owner = owner; + this.link = link; + this.caption = caption; + this.link_type = link_type; + this.video_id = video_id; + + } + + public void addCaption(String caption){ + this.caption = caption; + } + // 1 = small 2 = big + protected String getEmbedHtml(int size){ + + if(size == 1){ + if(link_type == 'y') + return ""; + else if (link_type == 'd') + return ""; + else if(link_type == 'v') + return ""; + else + return ""; + } + else if(size == 2){ + if(link_type == 'y') + return ""; + else if (link_type == 'd') + return ""; + else if(link_type == 'v') + return ""; + } + + return ""; + } + + public List comments() { + return Comment.find("parentObj = ? order by createdAt asc", this).fetch(); + } + + + + +} diff --git a/app/models/User.java b/app/models/User.java index 5db7924..1cda28e 100644 --- a/app/models/User.java +++ b/app/models/User.java @@ -107,6 +107,10 @@ public Profile getProfile(){ @ElasticSearchIgnore @OneToMany(mappedBy="owner") public Set questions; + + @ElasticSearchIgnore + @OneToMany(mappedBy = "owner", cascade=CascadeType.ALL) + public List videos; //videos of the user @OneToMany(mappedBy = "subscriber", cascade = CascadeType.ALL) public List feeds; diff --git a/app/views/Videos/listLinkedVideos.html b/app/views/Videos/listLinkedVideos.html new file mode 100644 index 0000000..36cd945 --- /dev/null +++ b/app/views/Videos/listLinkedVideos.html @@ -0,0 +1,59 @@ +#{extends 'two_panel.html' /} + +
+ +

Link a new video

+
+ +
+ + #{ifErrors} +
    + #{errors} +
  • ${error}
  • #{/errors} +
+ #{/ifErrors} + +
+ #{form @Videos.createLinkedVideo(), enctype:'multipart/form-data'} + + + + + + + + + + + + + + + +
+ +
+ #{/form} +
+ + +
+
+ +
\ No newline at end of file diff --git a/app/views/Videos/showLinkedVideo.html b/app/views/Videos/showLinkedVideo.html new file mode 100644 index 0000000..b40808e --- /dev/null +++ b/app/views/Videos/showLinkedVideo.html @@ -0,0 +1,53 @@ +#{extends 'two_panel.html' /} + +
+

${vid.title}

Posted by: ${vid.owner} +
+ #{verbatim} ${vid.getEmbedHtml(2)} #{/verbatim} + #{if vid.owner.equals(currentUser)} +
+ + Remove Video + +
+ #{/if} + +
+ ${vid.caption} +
+
+ +#{list items:vid.comments(), as:'comment'} + +
+ #{if comment.owner.equals(currentUser)} + + Remove Comment + +
+ #{/if} +
+ ${comment.owner}:
+
+
+
${comment.content.escape().nl2br()}
+
+
+ +#{/list} +
+#{form @Videos.addComment(), enctype:'multipart/form-data'} +
+
Post reply:
+ +
+ + +
+ +
+
+#{/form} + diff --git a/app/views/tags/lhsNav.html b/app/views/tags/lhsNav.html index 92f4319..5329468 100644 --- a/app/views/tags/lhsNav.html +++ b/app/views/tags/lhsNav.html @@ -16,6 +16,7 @@
  • Change Skin
  • Notes
  • Threads
  • +
  • Video
  • diff --git a/app/views/tags/post.html b/app/views/tags/post.html index 2927e97..77884fd 100644 --- a/app/views/tags/post.html +++ b/app/views/tags/post.html @@ -18,6 +18,11 @@
    #{/elseif} + #{if _item.getClass().getName() == "models.LinkedVideo"} +

    ${_item.title}

    + #{verbatim} ${_item.getEmbedHtml(1)} #{/verbatim} +
    ${_item.caption}
    + #{/if} #{elseif _item.getClass().getName() == "models.Question"}
    #{question currentUser:currentUser, question:_item /} diff --git a/conf/application.conf b/conf/application.conf index 7a7990b..24acd9f 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -216,6 +216,6 @@ elasticsearch.local=false # ~~~~~ #%test.module.cobertura=${play.path}/modules/cobertura %test.application.mode=dev -%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0 +%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0;TRACE_LEVEL_FILE=3 %test.jpa.ddl=create %test.mail.smtp=mock diff --git a/conf/routes b/conf/routes index 678cee9..f9bab85 100644 --- a/conf/routes +++ b/conf/routes @@ -127,6 +127,13 @@ GET /events/{<[0-9]+>eventId} Events.event #1 event GET /events/eventcreator Events.addEvent POST /events Events.addEvent +# Video +GET /users/{<[0-9]+>ownerId}/videos/linked/? Videos.listLinkedVideos +GET /videos/linked Videos.listMyLinkedVideos +POST /videos Videos.createLinkedVideo +DELETE /videos/linked/{<[0-9]+>photoId} Videos.removeLinkedVideo + + #Relationships GET /relationships Relationships.relationships @@ -148,6 +155,12 @@ GET /{Likeable}/{<[0-9]+>likeableId}/likes Likeables.likes POST /{Likeable}/{<[0-9]+>likeableId}/likes Likeables.like DELETE /{Likeable}/{<[0-9]+>likeableId}/likes Likeables.unLike +# Video +GET /users/{<[0-9]+>ownerId}/videos/linked/? Videos.listLinkedVideos +GET /videos/linked Videos.listMyLinkedVideos +POST /videos Videos.createLinkedVideo +DELETE /videos/linked/{<[0-9]+>photoId} Videos.removeLinkedVideo + # Ignore favicon requests GET /favicon.ico 404 diff --git a/public/bootstrap/docs/build/node_modules/.bin/hulk b/public/bootstrap/docs/build/node_modules/.bin/hulk deleted file mode 100755 index dd5c4a6..0000000 --- a/public/bootstrap/docs/build/node_modules/.bin/hulk +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env node - -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var hogan = require('../lib/hogan.js'), - path = require('path'), - fs = require('fs'); - -var specials = ['/', '.', '*', '+', '?', '|','(', ')', '[', ']', '{', '}', '\\'], - specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g'), - templates; - - -// Escape special regexp characters -function esc(text) { - return text.replace(specialsRegExp, '\\$1'); -} - - -// Check for dirs and correct ext (<3 for windows) -function extractFiles(args) { - var usage = 'USAGE: hulk ./templates/*.mustaches\n' + - 'NOTE: hulk supports the "*" wildcard and allows you to target specific extensions too', - files = []; - - if (!args.length) { - console.log(usage); - process.exit(-1); - } - - args.forEach(function (arg) { - - if (/\*/.test(arg)) { - arg = arg.split('*'); - return files = files.concat( - fs.readdirSync(arg[0] || '.') - .map(function (f) { - return new RegExp(esc(arg[1]) + '$').test(f) && path.join(arg[0], f); - }) - .filter(function (f) { - return f; - }) - ); - } - - files.push(arg); - - }) - - return files; -} - - -// Remove utf-8 byte order mark, http://en.wikipedia.org/wiki/Byte_order_mark -function removeByteOrderMark(text) { - if (text.charCodeAt(0) === 0xfeff) { - return text.substring(1); - } - return text; -} - - -// Write a template foreach file that matches template extension -templates = extractFiles(process.argv.slice(2)) - .map(function (file) { - var openedFile = fs.readFileSync(file, 'utf-8'), name; - if (!openedFile) return; - name = file.replace(/\..*$/, ''); - openedFile = removeByteOrderMark(openedFile.trim()); - return 'templates.' + name + ' = new Hogan.Template(' + hogan.compile(openedFile, { asString: 1 }) + ');'; - }) - .filter(function (t) { - return t; - }); - - -// Output templates -if (!templates.length) return; -console.log('var templates = {};'); -console.log(templates.join('\n')); \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/.git_ignore b/public/bootstrap/docs/build/node_modules/hogan.js/.git_ignore deleted file mode 100644 index 3c3629e..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/.git_ignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/.gitmodules b/public/bootstrap/docs/build/node_modules/hogan.js/.gitmodules deleted file mode 100644 index 6bfdc18..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "test/spec"] - path = test/spec - url = https://github.com/mustache/spec.git diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/Makefile b/public/bootstrap/docs/build/node_modules/hogan.js/Makefile deleted file mode 100644 index 922fdea..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -REPO = git@github.com:twitter/hogan.js.git -BUILD := build -VERSION = ${shell node -e 'var s = JSON.parse(require("fs").readFileSync("package.json").toString()).version; console.log(s.substring(0, s.indexOf("-")));'} - -# -# Run command line tests -# -test: - @ node test/index.js - -# -# Run Mustache spec tests -# -spec: - @ node test/spec.js - -# -# Run benchmark -# -benchmark: - @ node benchmark/console/index.js - -clean: - @ rm -rf dist/* -# -# Make a new version of Hogan from the current dev version. -# -release: clean - @ echo "Creating a new version of Hogan." - @ mkdir -p dist/nodejs - @ cp -R lib dist/nodejs/lib - @ node tools/release.js - @ mkdir -p web/builds/$(VERSION) - @ cp dist/*.* web/builds/$(VERSION)/. -# -# Make the gh-pages website -# -# This target builds the hogan.js github website using hogan.js. -# -# cd into build/gh-pages to check in the new site. -# -GH_PAGES = $(BUILD)/gh-pages -web: | pages - @cp -R web/* $(GH_PAGES) - @@ node tools/web_templates.js - @echo - @echo "Website built in $(GH_PAGES)." - -# -# Checkout the gh-pages branch. -# -pages: | $(BUILD) - @if [ ! -d "$(GH_PAGES)" ]; then \ - git clone -b gh-pages $(REPO) $(GH_PAGES); \ - rm -rf $(GH_PAGES)/*; \ - fi; - @mkdir -p $(GH_PAGES)/images - -$(BUILD): - mkdir -p $(BUILD) - -.PHONY: test spec benchmark web release diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/README.md b/public/bootstrap/docs/build/node_modules/hogan.js/README.md deleted file mode 100644 index e879894..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/README.md +++ /dev/null @@ -1,93 +0,0 @@ -## Hogan.js - A mustache compiler. - -[Hogan.js](http://twitter.github.com/hogan.js/) is a compiler for the -[Mustache](http://mustache.github.com/) templating language. For information -on Mustache, see the [manpage](http://mustache.github.com/mustache.5.html) and -the [spec](https://github.com/mustache/spec). - -## Basics - -Hogan compiles templates to HoganTemplate objects, which have a render method. - -```js -var data = { - screenName: "dhg", -}; - -var template = Hogan.compile("Follow @{{screenName}}."); -var output = template.render(data); - -// prints "Follow @dhg." -console.log(output); -``` - -## Features - -Hogan is fast--try it on your workload. - -Hogan has separate scanning, parsing and code generation phases. This way it's -possible to add new features without touching the scanner at all, and many -different code generation techniques can be tried without changing the parser. - -Hogan exposes scan and parse methods. These can be useful for -pre-processing templates on the server. - -```js -var text = "{{^check}}{{i18n}}No{{/i18n}}{{/check}}"; -text += "{{#check}}{{i18n}}Yes{{/i18n}}{{/check}}"; -var tree = Hogan.parse(Hogan.scan(text)); - -// outputs "# check" -console.log(tree[0].tag + " " + tree[0].name); - -// outputs "Yes" -console.log(tree[1].nodes[0].nodes[0]); -``` - -It's also possible to use HoganTemplate objects without the Hogan compiler -present. That means you can pre-compile your templates on the server, and -avoid shipping the compiler. However, the optional lambda features from the -Mustache spec do require the compiler to be present. - -## Why Hogan.js? - -Why another templating library? - -Hogan.js was written to meet three templating library requirements: good -performance, standalone template objects, and a parser API. - -## Issues - -Have a bug? Please create an issue here on GitHub! - -https://github.com/twitter/hogan.js/issues - -## Versioning - -For transparency and insight into our release cycle, releases will be numbered with the follow format: - -`..` - -And constructed with the following guidelines: - -* Breaking backwards compatibility bumps the major -* New additions without breaking backwards compatibility bumps the minor -* Bug fixes and misc changes bump the patch - -For more information on semantic versioning, please visit http://semver.org/. - -## Authors - -**Robert Sayre** - -+ http://github.com/sayrer - -**Jacob Thornton** - -+ http://github.com/fat - -## License - -Copyright 2011 Twitter, Inc. - -Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/bin/hulk b/public/bootstrap/docs/build/node_modules/hogan.js/bin/hulk deleted file mode 100755 index dd5c4a6..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/bin/hulk +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env node - -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var hogan = require('../lib/hogan.js'), - path = require('path'), - fs = require('fs'); - -var specials = ['/', '.', '*', '+', '?', '|','(', ')', '[', ']', '{', '}', '\\'], - specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g'), - templates; - - -// Escape special regexp characters -function esc(text) { - return text.replace(specialsRegExp, '\\$1'); -} - - -// Check for dirs and correct ext (<3 for windows) -function extractFiles(args) { - var usage = 'USAGE: hulk ./templates/*.mustaches\n' + - 'NOTE: hulk supports the "*" wildcard and allows you to target specific extensions too', - files = []; - - if (!args.length) { - console.log(usage); - process.exit(-1); - } - - args.forEach(function (arg) { - - if (/\*/.test(arg)) { - arg = arg.split('*'); - return files = files.concat( - fs.readdirSync(arg[0] || '.') - .map(function (f) { - return new RegExp(esc(arg[1]) + '$').test(f) && path.join(arg[0], f); - }) - .filter(function (f) { - return f; - }) - ); - } - - files.push(arg); - - }) - - return files; -} - - -// Remove utf-8 byte order mark, http://en.wikipedia.org/wiki/Byte_order_mark -function removeByteOrderMark(text) { - if (text.charCodeAt(0) === 0xfeff) { - return text.substring(1); - } - return text; -} - - -// Write a template foreach file that matches template extension -templates = extractFiles(process.argv.slice(2)) - .map(function (file) { - var openedFile = fs.readFileSync(file, 'utf-8'), name; - if (!openedFile) return; - name = file.replace(/\..*$/, ''); - openedFile = removeByteOrderMark(openedFile.trim()); - return 'templates.' + name + ' = new Hogan.Template(' + hogan.compile(openedFile, { asString: 1 }) + ');'; - }) - .filter(function (t) { - return t; - }); - - -// Output templates -if (!templates.length) return; -console.log('var templates = {};'); -console.log(templates.join('\n')); \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/lib/compiler.js b/public/bootstrap/docs/build/node_modules/hogan.js/lib/compiler.js deleted file mode 100644 index 2cd65f6..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/lib/compiler.js +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -(function (Hogan) { - // Setup regex assignments - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/, - rQuot = /\"/g, - rNewline = /\n/g, - rCr = /\r/g, - rSlash = /\\/g, - tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - Hogan.scan = function scan(text, delimiters) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - tag = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart, next; j < tokens.length; j++) { - if (!tokens[j].tag) { - if ((next = tokens[j+1]) && next.tag == '>') { - // set indent to token value - next.indent = tokens[j].toString() - } - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}); - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag, - closeIndex = text.indexOf(close, index), - delimiters = trim( - text.substring(text.indexOf('=', index) + 1, closeIndex) - ).split(' '); - - otag = delimiters[0]; - ctag = delimiters[1]; - - return closeIndex + close.length - 1; - } - - if (delimiters) { - delimiters = delimiters.split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text.charAt(i) == '\n') { - filterLine(seenTag); - } else { - buf += text.charAt(i); - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - tag = tagTypes[text.charAt(i + 1)]; - tagType = tag ? text.charAt(i + 1) : '_v'; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - seenTag = i; - } else { - if (tagChange(ctag, text, i)) { - tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, - i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); - buf = ''; - i += ctag.length - 1; - state = IN_TEXT; - if (tagType == '{') { - if (ctag == '}}') { - i++; - } else { - cleanTripleStache(tokens[tokens.length - 1]); - } - } - } else { - buf += text.charAt(i); - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function cleanTripleStache(token) { - if (token.n.substr(token.n.length - 1) === '}') { - token.n = token.n.substring(0, token.n.length - 1); - } - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - function tagChange(tag, text, index) { - if (text.charAt(index) != tag.charAt(0)) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text.charAt(index + i) != tag.charAt(i)) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length === 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function writeCode(tree) { - return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;'; - } - - Hogan.generate = function (code, text, options) { - if (options.asString) { - return 'function(c,p,i){' + code + ';}'; - } - - return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan); - } - - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r'); - } - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i]); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text('"' + esc(tree[i]) + '"'); - } - } - return code; - } - - function section(nodes, id, method, start, end, tags) { - return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + - 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' + - 'b += _.rs(c,p,' + - 'function(c,p){ var b = "";' + - walk(nodes) + - 'return b;});c.pop();}' + - 'else{b += _.b; _.b = ""};'; - } - - function invertedSection(nodes, id, method) { - return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + - walk(nodes) + - '};'; - } - - function partial(tok) { - return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += ' + id + ';'; - } - - Hogan.parse = function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - Hogan.cache = {}; - - Hogan.compile = function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - // delimiters: A string that overrides the default delimiters. - // Example: "<% %>" - // - options = options || {}; - - var key = text + '||' + !!options.asString; - - var t = this.cache[key]; - - if (t) { - return t; - } - - t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options); - return this.cache[key] = t; - }; -})(typeof exports !== 'undefined' ? exports : Hogan); diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/lib/hogan.js b/public/bootstrap/docs/build/node_modules/hogan.js/lib/hogan.js deleted file mode 100644 index f0119b5..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/lib/hogan.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// This file is for use with Node.js. See dist/ for browser files. - -var Hogan = require('./compiler'); -Hogan.Template = require('./template').Template; -module.exports = Hogan; \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/lib/template.js b/public/bootstrap/docs/build/node_modules/hogan.js/lib/template.js deleted file mode 100644 index 8958a70..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/lib/template.js +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var Hogan = {}; - -(function (Hogan) { - Hogan.Template = function constructor(renderFunc, text, compiler) { - if (renderFunc) { - this.r = renderFunc; - } - this.c = compiler; - this.text = text || ''; - } - - Hogan.Template.prototype = { - // render: replaced by generated code. - r: function (context, partials, indent) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials, indent) { - return this.ri([context], partials || {}, indent); - }, - - // render internal -- a hook for overrides that catches partials too - ri: function (context, partials, indent) { - return this.r(context, partials, indent); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - if (this.c && typeof partial == 'string') { - partial = this.c.compile(partial); - } - - return partial.ri(context, partials, indent); - }, - - // render a section - rs: function(context, partials, section) { - var buf = '', - tail = context[context.length - 1]; - - if (!isArray(tail)) { - return buf = section(context, partials); - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end, tags) { - var pass; - - if (isArray(val) && val.length === 0) { - return false; - } - - if (typeof val == 'function') { - val = this.ls(val, ctx, partials, inverted, start, end, tags); - } - - pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - var names = key.split('.'), - val = this.f(names[0], ctx, partials, returnFound), - cx = null; - - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false, - v = null, - found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var compiler = this.c; - var t = val.call(cx, text, function(t) { - return compiler.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, inverted, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = null; - - if (!inverted && this.c && val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - t = val.call(cx); - - if (typeof t == 'function') { - if (inverted) { - return true; - } else if (this.c) { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - var result = val.call(cx); - if (typeof result == 'function') { - result = result.call(cx); - } - result = result.toString(); - - if (this.c && ~result.indexOf("{{")) { - return this.c.compile(result).render(cx, partials); - } - - return result; - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String((str === null || str === undefined) ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - -})(typeof exports !== 'undefined' ? exports : Hogan); - diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/package.json b/public/bootstrap/docs/build/node_modules/hogan.js/package.json deleted file mode 100644 index a09dede..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "hogan.js" - , "description": "A mustache compiler." - , "version": "1.0.5-dev" - , "keywords": ["mustache", "template"] - , "main": "./lib/hogan.js" - , "homepage": "http://twitter.github.com/hogan.js/" - , "author": "Twitter Inc." - , "repository": { - "type": "git" - , "url": "https://github.com/twitter/hogan.js.git" - } - , "licenses": [ - { "type": "Apache-2.0" - , "url": "http://www.apache.org/licenses/LICENSE-2.0" - } - ] - , "devDependencies": { "uglify-js": "*" } - , "bin" : { "hulk" : "./bin/hulk" } -} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/html/list.html b/public/bootstrap/docs/build/node_modules/hogan.js/test/html/list.html deleted file mode 100644 index 9bb653a..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/html/list.html +++ /dev/null @@ -1,8 +0,0 @@ -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/index.html b/public/bootstrap/docs/build/node_modules/hogan.js/test/index.html deleted file mode 100644 index 6f0e743..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - test - - - - - - - - - - \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/index.js b/public/bootstrap/docs/build/node_modules/hogan.js/test/index.js deleted file mode 100644 index 9b235eb..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/index.js +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var Hogan = Hogan || require('../lib/hogan') - , doc = this["document"] - -function testScanTextNoTags() { - var text = "

    hi

    "; - var tokens = Hogan.scan(text); - is(tokens.length, 1, "One token"); - is(tokens[0]+'', text, "text is equal to first token"); -} - -function testScanOneTag() { - var text = "{{hmm}}"; - var tokens = Hogan.scan(text); - is(tokens.length, 1, "One token"); - is(tokens[0].n, "hmm", "First token content is variable name."); -} - -function testScanMultipleTags() { - var text = "asdf{{hmm}}asdf2{{hmm2}}asdf3"; - var tokens = Hogan.scan(text); - is(tokens.length, 5, "3 text tokens, 2 tag tokens."); - is(tokens[0]+'', "asdf", "first token is text"); - is(tokens[1].n, "hmm", "second token is tag"); - is(tokens[1].tag, "_v", "second token is a variable"); - is(tokens[2]+'', "asdf2", "third token is text"); - is(tokens[3].n, "hmm2", "fourth token is tag"); - is(tokens[3].tag, "_v", "fourth token is a variable"); - is(tokens[4]+'', "asdf3", "Fifth token is text"); -} - -function testScanSectionOpen() { - var text = "{{#hmm}}"; - var tokens = Hogan.scan(text); - is(tokens.length, 1, "One token"); - is(tokens[0].n, "hmm", "First token content is variable name."); - is(tokens[0].tag, "#", "First token is a section."); -} - -function testScanSectionClose() { - var text = "{{/hmm}}"; - var tokens = Hogan.scan(text); - is(tokens.length, 1, "One token"); - is(tokens[0].n, "hmm", "First token content is variable name."); - is(tokens[0].tag, "/", "First token is a section."); -} - -function testScanSection() { - var text = "{{#hmm}}{{/hmm}}"; - var tokens = Hogan.scan(text); - is(tokens.length, 2, "One token"); - is(tokens[0].n, "hmm", "First token content is variable name."); - is(tokens[0].tag, "#", "First token is a section."); - is(tokens[1].n, "hmm", "Second token content is variable name."); - is(tokens[1].tag, "/", "Second token is a section."); -} - -function testScanSectionInContent() { - var text = "abc{{#hmm}}def{{/hmm}}ghi"; - var tokens = Hogan.scan(text); - is(tokens.length, 5, "3 text tokens, 2 tag tokens."); - is(tokens[0]+'', "abc", "first token is text"); - is(tokens[1].n, "hmm", "second token is tag"); - is(tokens[1].tag, "#", "second token is a variable"); - is(tokens[2]+'', "def", "third token is text"); - is(tokens[3].n, "hmm", "fourth token is tag"); - is(tokens[3].tag, "/", "fourth token is a variable"); - is(tokens[4]+'', "ghi", "Fifth token is text"); -} - -function testScanNegativeSection() { - var text = "{{^hmm}}{{/hmm}}"; - var tokens = Hogan.scan(text); - is(tokens.length, 2, "One token"); - is(tokens[0].n, "hmm", "First token content is variable name."); - is(tokens[0].tag, "^", "First token is a negative section."); - is(tokens[1].n, "hmm", "First token content is variable name."); - is(tokens[1].tag, "/", "Second token is a section."); -} - -function testScanPartial() { - var text = "{{>hmm}}"; - var tokens = Hogan.scan(text); - is(tokens.length, 1, "One token"); - is(tokens[0].n, "hmm", "First token content is variable name."); - is(tokens[0].tag, ">", "First token is a partial."); -} - - -function testScanBackwardPartial() { - var text = "{{
    \' \" &"}); - is(s, "< > <div> ' " &", "input correctly escaped."); - - var ec ={ "'": "'", '"': """, "<": "<", ">": ">", "&": "&"} - for (var char in ec) { - var s = t.render({foo: char + " just me"}); - is(s, ec[char] + " just me", "input correctly escaped."); - } - -} - -function testMustacheInjection() { - var text = "{{foo}}"; - var t = Hogan.compile(text); - s = t.render({foo:"{{{<42}}}"}) - is(s, "{{{<42}}}", "Can't inject mustache"); -} - -function testTripleStache() { - var text = "{{{foo}}}"; - var t = Hogan.compile(text); - var s = t.render({foo: "< >
    \' \" &"}); - is(s, "< >
    \' \" &", "input correctly not-escaped."); -} - -function testAmpNoEscaping() { - var text = "{{&foo}}"; - var t = Hogan.compile(text); - var s = t.render({foo: "< >
    \' \" &"}); - is(s, "< >
    \' \" &", "input correctly not-escaped."); -} - -function testPartial() { - var partialText = "this is text from the partial--the magic number {{foo}} is from a variable"; - var p = Hogan.compile(partialText); - - var text = "This template contains a partial ({{>testPartial}})." - var t = Hogan.compile(text); - - var s = t.render({foo: 42}, {testPartial: p}); - is(s, "This template contains a partial (this is text from the partial--the magic number 42 is from a variable).", "partials work"); -} - -function testNestedPartials() { - var partialText = "this is text from the partial--the magic number {{foo}} is from a variable"; - var p = Hogan.compile(partialText); - - var partialText2 = "This template contains a partial ({{>testPartial}})." - var p2 = Hogan.compile(partialText2); - - var text = "This template contains a partial that contains a partial [{{>testPartial2}}]." - var t = Hogan.compile(text); - - var s = t.render({foo: 42}, {testPartial: p, testPartial2: p2}); - is(s, "This template contains a partial that contains a partial [This template contains a partial (this is text from the partial--the magic number 42 is from a variable).].", "nested partials work"); -} - -function testNegativeSection() { - var text = "This template {{^foo}}BOO {{/foo}}contains an inverted section." - var t = Hogan.compile(text); - var s = t.render(); - is(s, "This template BOO contains an inverted section.", "inverted sections with no context work"); - - s = t.render({foo:[]}); - is(s, "This template BOO contains an inverted section.", "inverted sections with empty list context work"); - - s = t.render({ foo:false }); - is(s, "This template BOO contains an inverted section.", "inverted sections with false context work"); - - s = t.render({foo:''}); - is(s, "This template contains an inverted section.", "inverted sections with empty string context work"); - - s = t.render({foo:true}); - is(s, "This template contains an inverted section.", "inverted sections with true context work"); - - s = t.render({foo: function() { return false; }}); - is(s, "This template BOO contains an inverted section.", "inverted sections with false returning method in context work"); -} - -function testSectionElision() { - var text = "This template {{#foo}}BOO {{/foo}}contains a section." - var t = Hogan.compile(text); - var s = t.render(); - is(s, "This template contains a section.", "sections with no context work"); - - s = t.render({foo:[]}); - is(s, "This template contains a section.", "sections with empty list context work"); - - s = t.render({foo:false}); - is(s, "This template contains a section.", "sections with false context work"); -} - -function testSectionObjectContext() { - var text = "This template {{#foo}}{{bar}} {{/foo}}contains a section." - var t = Hogan.compile(text); - var s = t.render({foo:{bar:42}}); - is(s, "This template 42 contains a section.", "sections with object context work"); -} - -function testSectionArrayContext() { - var text = "This template {{#foo}}{{bar}} {{/foo}}contains a section." - var t = Hogan.compile(text); - var s = t.render({foo:[{bar:42}, {bar:43}, {bar:44}]}); - is(s, "This template 42 43 44 contains a section.", "sections with object ctx and array values work"); -} - -function testFalsyVariableNoRender() { - var text = "I ({{cannot}}) be seen!"; - var t = Hogan.compile(text); - var s = t.render(); - is(s, "I () be seen!", "missing value doesn't render."); -} - -function testSectionExtensions() { - var text = "Test {{_//|__foo}}bar{{/foo}}"; - var options = {sectionTags:[{o:'_//|__foo', c:'foo'}]}; - var tree = Hogan.parse(Hogan.scan(text), options); - is(tree[1].tag, "#", "_//|__foo node transformed to section"); - is(tree[1].n, "_//|__foo", "_//|__foo node transformed to section"); - - var t = Hogan.compile(text, options ); - var s = t.render({'_//|__foo':true}); - is(s, "Test bar", "Custom sections work"); -} - -function testMisnestedSectionExtensions() { - var text = "Test {{__foo}}bar{{/bar}}"; - var options = {sectionTags:[{o:'__foo', c:'foo'}, {o:'__bar', c:'bar'}]}; - var msg = ''; - try { - var tree = Hogan.parse(Hogan.scan(text), options); - } catch (e) { - msg = e.message; - } - is(msg, "Nesting error: __foo vs. bar", "Error is generated"); -} - -function testNestedSection() { - var text = "{{#foo}}{{#bar}}{{baz}}{{/bar}}{{/foo}}"; - var t = Hogan.compile(text); - var s = t.render({foo: 42, bar: 42, baz:42}); - is(s, "42", "can reach up context stack"); -} - -function testDottedNames() { - var text = '"{{person.name}}" == "{{#person}}{{name}}{{/person}}"'; - var t = Hogan.compile(text); - var s = t.render({person:{name:'Joe'}}); - is(s, '"Joe" == "Joe"', "dotted names work"); -} - -function testImplicitIterator() { - var text = '{{#stuff}} {{.}} {{/stuff}}'; - var t = Hogan.compile(text); - var s = t.render({stuff:[42,43,44]}); - is(s, " 42 43 44 ", "implicit iterators work"); -} - -function testPartialsAndDelimiters() { - var text = '{{>include}}*\n{{= | | =}}\n*|>include|'; - var partialText = ' .{{value}}. '; - var partial = Hogan.compile(partialText); - var t = Hogan.compile(text); - var s = t.render({value:"yes"}, {'include':partial}); - is(s, " .yes. *\n* .yes. ", "partials work around delimiters"); -} - -function testStringPartials() { - var text = "foo{{>mypartial}}baz"; - var partialText = " bar "; - var t = Hogan.compile(text); - var s = t.render({}, {'mypartial': partialText}); - is(s, "foo bar baz", "string partial works."); -} - -function testMissingPartials() { - var text = "foo{{>mypartial}} bar"; - var t = Hogan.compile(text); - var s = t.render({}); - is(s, "foo bar", "missing partial works."); -} - -function testIndentedStandaloneComment() { - var text = 'Begin.\n {{! Indented Comment Block! }}\nEnd.'; - var t = Hogan.compile(text); - var s = t.render(); - is(s, 'Begin.\nEnd.', "Standalone comment blocks are removed."); -} - -function testNewLineBetweenDelimiterChanges() { - var data = { section: true, data: 'I got interpolated.' }; - var text = '\n{{#section}}\n {{data}}\n |data|\n{{/section}}x\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|'; - var t = Hogan.compile(text); - var s = t.render(data); - is(s, '\n I got interpolated.\n |data|\nx\n\n {{data}}\n I got interpolated.\n', 'render correct') -} - -function testMustacheJSApostrophe() { - var text = '{{apos}}{{control}}'; - var t = Hogan.compile(text); - var s = t.render({'apos':"'", 'control':"X"}); - is(s, ''X', 'Apostrophe is escaped.'); -} - -function testMustacheJSArrayOfImplicitPartials() { - var text = 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}\n'; - var partialText = '{{.}}\n'; - var t = Hogan.compile(text); - var s = t.render({numbers:[1,2,3,4]}, {partial: partialText}); - is(s, 'Here is some stuff!\n1\n2\n3\n4\n', 'Partials with implicit iterators work.'); -} - -function testMustacheJSArrayOfPartials() { - var text = 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}\n'; - var partialText = '{{i}}\n'; - var t = Hogan.compile(text); - var s = t.render({numbers:[{i:1},{i:2},{i:3},{i:4}]}, {partial: partialText}); - is(s, 'Here is some stuff!\n1\n2\n3\n4\n', 'Partials with arrays work.'); -} - -function testMustacheJSArrayOfStrings() { - var text = '{{#strings}}{{.}} {{/strings}}'; - var t = Hogan.compile(text); - var s = t.render({strings:['foo', 'bar', 'baz']}); - is(s, 'foo bar baz ', 'array of strings works with implicit iterators.'); -} - -function testMustacheJSUndefinedString() { - var text = 'foo{{bar}}baz'; - var t = Hogan.compile(text); - var s = t.render({bar:undefined}); - is(s, 'foobaz', 'undefined value does not render.'); -} - -function testMustacheJSTripleStacheAltDelimiter() { - var text = '{{=<% %>=}}<% foo %> {{foo}} <%{bar}%> {{{bar}}}'; - var t = Hogan.compile(text); - var s = t.render({foo:'yeah', bar:'hmm'}); - is(s, 'yeah {{foo}} hmm {{{bar}}}', 'triple stache inside alternate delimiter works.'); -} - -/* shootout benchmark tests */ - -function testShootOutString() { - var text = "Hello World!"; - var expected = "Hello World!" - var t = Hogan.compile(text) - var s = t.render({}) - is(s, expected, "Shootout String compiled correctly"); -} - -function testShootOutReplace() { - var text = "Hello {{name}}! You have {{count}} new messages."; - var expected = "Hello Mick! You have 30 new messages."; - var t = Hogan.compile(text) - var s = t.render({ name: "Mick", count: 30 }) - is(s, expected, "Shootout Replace compiled correctly"); -} - -function testShootOutArray() { - var text = "{{#names}}{{name}}{{/names}}"; - var expected = "MoeLarryCurlyShemp"; - var t = Hogan.compile(text); - var s = t.render({ names: [{name: "Moe"}, {name: "Larry"}, {name: "Curly"}, {name: "Shemp"}] }) - is(s, expected, "Shootout Array compiled correctly"); -} - -function testShootOutObject() { - var text = "{{#person}}{{name}}{{age}}{{/person}}"; - var expected = "Larry45"; - var t = Hogan.compile(text) - var s = t.render({ person: { name: "Larry", age: 45 } }) - is(s, expected, "Shootout Object compiled correctly"); -} - -function testShootOutPartial() { - var text = "{{#peeps}}{{>replace}}{{/peeps}}"; - var t = Hogan.compile(text); - var partial = Hogan.compile(" Hello {{name}}! You have {{count}} new messages."); - var s = t.render({ peeps: [{name: "Moe", count: 15}, {name: "Larry", count: 5}, {name: "Curly", count: 2}] }, { replace: partial }); - var expected = " Hello Moe! You have 15 new messages. Hello Larry! You have 5 new messages. Hello Curly! You have 2 new messages."; - is(s, expected, "Shootout Partial compiled correctly"); -} - -function testShootOutRecurse() { - var text = "{{name}}{{#kids}}{{>recursion}}{{/kids}}"; - var t = Hogan.compile(text); - var partial = Hogan.compile("{{name}}{{#kids}}{{>recursion}}{{/kids}}"); - var s = t.render({ - name: '1', - kids: [ - { - name: '1.1', - kids: [ - { name: '1.1.1', kids: [] } - ] - } - ] - }, { recursion: partial }); - var expected = "11.11.1.1"; - is(s, expected, "Shootout Recurse compiled correctly"); -} - -function testShootOutFilter() { - var text = "{{#filter}}foo {{bar}}{{/filter}}"; - var t = Hogan.compile(text); - var s = t.render({ - filter: function() { - return function(text, render) { - return render(text).toUpperCase(); - } - }, - bar: "bar" - }); - var expected = "FOO BAR" - is(s, expected, "Shootout Filter compiled correctly"); -} - -function testShootOutComplex() { - var text = - "

    {{header}}

    " + - "{{#hasItems}}" + - "
      " + - "{{#items}}" + - "{{#current}}" + - "
    • {{name}}
    • " + - "{{/current}}" + - "{{^current}}" + - "
    • {{name}}
    • " + - "{{/current}}" + - "{{/items}}" + - "
    " + - "{{/hasItems}}" + - "{{^hasItems}}" + - "

    The list is empty.

    " + - "{{/hasItems}}"; - - var expected = "

    Colors

    "; - var t = Hogan.compile(text) - var s = t.render({ - header: function() { - return "Colors"; - }, - items: [ - {name: "red", current: true, url: "#Red"}, - {name: "green", current: false, url: "#Green"}, - {name: "blue", current: false, url: "#Blue"} - ], - hasItems: function() { - return this.items.length !== 0; - }, - empty: function() { - return this.items.length === 0; - } - }) - - is(s, expected, "Shootout Complex compiled correctly"); -} - -function testRenderOutput() { - if (doc) return - var fs = require('fs'); - var inPath = 'test/templates'; - var outPath = 'test/html'; - - fs.readdirSync(inPath).forEach(function (file) { - var i = fs.readFileSync([inPath, file].join('/'), 'utf-8'); - var t = Hogan.compile(i); - var r = t.render({}); - var o = fs.readFileSync([outPath, file].join('/').replace(/mustache$/, 'html')).toString(); - is(r === o, true, file + ' should correctly render html') - }) -} - -function testDefaultRenderImpl() { - var ht = new Hogan.Template(); - is(ht.render() === '', true, 'default renderImpl returns an array.'); -} - - -function appendText(el, text) { - var textNode = document.createTextNode(text); - el.appendChild(textNode); - el.appendChild(document.createElement('br')); -} - -if (!this["output"]) { - var output = function (s) { - return doc ? appendText(doc.getElementById('console'), s) : console.log(s); - }; -} -var passed = 0; -var failed = 0; - -function is(got, expected, msg) { - if (got === expected) { - output("OK: " + msg); - ++passed; - } else { - output("FAIL: " + msg); - output("Expected |" + expected + "|"); - output(" Got |" + got + "|"); - ++failed; - } -} - -function complete() { - output("\nTests Complete"); - output("--------------"); - output("Passed: " + passed); - output("Failed: " + failed); - output("\n"); -} - -function runTests() { - output("Tests Starting"); - output("--------------"); - testScanTextNoTags(); - testScanOneTag(); - testScanMultipleTags(); - testScanSectionOpen(); - testScanSectionClose(); - testScanSection(); - testScanSectionInContent(); - testScanNegativeSection(); - testScanPartial(); - testScanBackwardPartial(); - testScanAmpersandNoEscapeTag(); - testScanTripleStache(); - testScanSectionWithTripleStacheInside(); - testScanSetDelimiter(); - testScanResetDelimiter(); - testSetDelimiterWithWhitespace(); - testSingleCharDelimiter(); - testParseBasic(); - testParseVariables(); - testParseSection(); - testParseIndexes(); - testParseNegativeSection(); - testParseNestedSections(); - testMissingClosingTag(); - testBadNesting(); - testBasicOutput(); - //testBasicOutputAsString(); - testOneVariable(); - //testOneVariableAsString(); - testMultipleVariables(); - testNumberValues(); - testObjectRender(); - testObjectToStringRender(); - testArrayRender(); - testEscaping(); - testMustacheInjection(); - testTripleStache(); - testAmpNoEscaping(); - testPartial(); - testNestedPartials(); - testNegativeSection(); - testSectionElision(); - testSectionObjectContext(); - testSectionArrayContext(); - testRenderWithWhitespace(); - testRenderWithWhitespaceAroundTripleStache(); - testRenderWithWhitespaceAroundAmpersand(); - testFalsyVariableNoRender(); - testRenderOutput(); - testDefaultRenderImpl(); - testSectionExtensions(); - testMisnestedSectionExtensions(); - testNestedSection(); - testShootOutString(); - testShootOutReplace(); - testShootOutArray(); - testShootOutObject(); - testShootOutPartial(); - testShootOutRecurse(); - testShootOutFilter(); - testShootOutComplex(); - testDottedNames(); - testImplicitIterator(); - testPartialsAndDelimiters(); - testStringPartials(); - testMissingPartials(); - testIndentedStandaloneComment(); - testNewLineBetweenDelimiterChanges(); - testMustacheJSApostrophe(); - testMustacheJSArrayOfImplicitPartials(); - testMustacheJSArrayOfPartials(); - testMustacheJSArrayOfStrings(); - testMustacheJSUndefinedString(); - testMustacheJSTripleStacheAltDelimiter(); - complete(); -} - -if (doc) { - window.onload = runTests; -} else { - runTests(); -} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/mustache.js b/public/bootstrap/docs/build/node_modules/hogan.js/test/mustache.js deleted file mode 100644 index b2d8ebc..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/mustache.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var doc = this['document']; -var fs = require('fs'); - -var passed = 0; -var failed = 0; - -if (!this['output']) { - var output = function (string) { - return doc ? doc.write(string + '
    ') : console.log(string); - }; -} - -var Hogan = require(__dirname + '/../lib/hogan'); -var template = fs.readFileSync(__dirname + '/../lib/template.js').toString(); -var compiler = fs.readFileSync(__dirname + '/../lib/compiler.js').toString(); -var mustache_wrapper = fs.readFileSync(__dirname + '/../wrappers/mustache.js.mustache').toString(); - -// Create a Mustache.js emulator from the distribution template -var engines = (new Function(Hogan.compile(mustache_wrapper).render({template: template, compiler: compiler}) + - '; return {Hogan: Hogan, Mustache: Mustache};'))(); - -var Mustache = engines.Mustache; -var Hogan2 = engines.Hogan; - - -// sanity check -is(Mustache.hasOwnProperty('to_html'), true, 'Mustache has to_html method.'); - -// Check for Mustache.js partial resolution behavior. -var context = { - foo: 'bar', - mypartial: { - baz: 'qux' - } -} -var text = 'abc {{foo}} def {{>mypartial}} ghi'; -var partialText = '{{baz}}'; -var s = Mustache.to_html(text, context, {'mypartial': partialText}); -is(s, 'abc bar def qux ghi', 'Correct emulation of Mustache.js partial-name-in-context resolution.'); - -// Now check to see that the Hogan resolution is unaffected. -var t = Hogan2.compile(text); -s = t.render(context, {'mypartial': partialText}); -is(s, 'abc bar def ghi', 'Hogan behavior not changed by Mustache.js emulation.'); - -// Check for sendFun behavior -var buf = ""; -function send(s) { - buf += "-FOO " + s + " FOO-"; -} -var s = Mustache.to_html(text, context, {'mypartial': partialText}, send); -is(buf, '-FOO abc bar def qux ghi FOO-', 'Correct emulation of Mustache.js sendFun.'); - - -function is(got, expected, msg) { - if (got === expected) { - output("OK: " + msg); - ++passed; - } else { - output("FAIL: " + msg); - output("Expected |" + expected + "|"); - output(" Got |" + got + "|"); - ++failed; - } -} - -function complete() { - output("\nTests Complete"); - output("--------------"); - output("Passed: " + passed); - output("Failed: " + failed); - output("\n"); -} - -complete(); \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec.js b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec.js deleted file mode 100644 index 15b4d8e..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var Hogan = Hogan || require('../lib/hogan'); -var doc = this["document"]; -var fs = require('fs'); - -var passed = 0; -var failed = 0; - -if (!this["output"]) { - var output = function (string) { - return doc ? doc.write(string + '
    ') : console.log(string); - }; -} - -function runTest(tests) { - tests.forEach(function(test) { - var partials = {}; - for (var i in test.partials) { - partials[i] = Hogan.compile(test.partials[i]); - } - var t = Hogan.compile(test.template); - - if (test.data.lambda) { - var func = (new Function ('return ' + test.data.lambda.js)()); - test.data.lambda = function() { return func; }; - } - - var s = t.render(test.data, partials); - is(s, test.expected, test.name + ': ' + test.desc); - }); -} - -var testDir = './test/spec/specs'; -var files = fs.readdirSync(testDir) - .filter(function(f) { return f.indexOf('.json') > 0; }) - .map(function(f) { return testDir + '/' + f}); - -for (var i = 0; i < files.length; i++) { - var test = JSON.parse(fs.readFileSync(files[i]).toString()); - runTest(test.tests); -} - -function is(got, expected, msg) { - if (got === expected) { - output("OK: " + msg); - ++passed; - } else { - output("FAIL: " + msg); - output("Expected |" + expected + "|"); - output(" Got |" + got + "|"); - ++failed; - } -} - -function complete() { - output("\nTests Complete"); - output("--------------"); - output("Passed: " + passed); - output("Failed: " + failed); - output("\n"); -} - -complete(); diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/Changes b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/Changes deleted file mode 100644 index bb39b98..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/Changes +++ /dev/null @@ -1,31 +0,0 @@ -2011-03-20: v1.1.2 - Added tests for standalone tags at string boundaries. - Added tests for rendering lambda returns after delimiter changes. - -2011-03-20: v1.0.3 - Added tests for standalone tags at string boundaries. - Added tests for rendering lambda returns after delimiter changes. - -2011-03-05: v1.1.1 - Added tests for indented inline sections. - Added tests for Windows-style newlines. - -2011-03-05: v1.0.2 - Added tests for indented inline sections. - Added tests for Windows-style newlines. - -2011-03-04: v1.1.0 - Implicit iterators. - A single period (`.`) may now be used as a name in Interpolation tags, - which represents the top of stack (cast as a String). - Dotted names. - Names containing one or more periods should be resolved as chained - properties; naïvely, this is like nesting section tags, but with some - built-in scoping protections. - -2011-03-02: v1.0.1 - Clarifying a point in the README about version compliance. - Adding high-level documentation to each spec file. - -2011-02-28: v1.0.0 - Initial Release diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/README.md b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/README.md deleted file mode 100644 index b01b1bb..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/README.md +++ /dev/null @@ -1,65 +0,0 @@ -The repository at https://github.com/mustache/spec is the formal standard for -Mustache. It defines both normal usage and edge-case behavior for libraries -parsing the Mustache templating language (or a superset thereof). - -The specification is developed as a series of YAML files, under the `specs` -directory. - -Versioning ----------- -This specification is being [semantically versioned](http://semver.org). -Roughly described, major version changes will always represent backwards -incompatible changes, minor version changes will always represent new language -features and will be backwards compatible, and patch ('tiny') version changes -will always be bug fixes. For the purposes of semantic versioning, the public -API is the contents of the `specs` directory and the algorithm for testing -against it. - -Mustache implementations SHOULD report the most recent version of the spec -(major and minor version numbers). If an implementation has support for any -optional modules, they SHOULD indicate so with a remark attached to the -version number (e.g. "vX.Y, including lambdas" or "v.X.Y+λ"). It is -RECOMMENDED that implementations not supporting at least v1.0.0 of this spec -refer to themselves as "Mustache-like", or "Mustache-inspired". - -Alternate Formats ------------------ - -Since YAML is a reasonably complex format that not every language has good -tools for working with, we also provide JSON versions of the specs on a -best-effort basis. - -These should be identical to the YAML specifications, but if you find the need -to regenerate them, they can be trivially rebuilt by invoking `rake build`. - -It is also worth noting that some specifications (notably, the lambda module) -rely on YAML "tags" to denote special types of data (e.g. source code). Since -JSON offers no way to denote this, a special key ("`__tag__`") is injected -with the name of the tag as its value. See `TESTING.md` for more information -about handling tagged data. - -Optional Modules ----------------- - -Specification files beginning with a tilde (`~`) describe optional modules. -At present, the only module being described as optional is regarding support -for lambdas. As a guideline, a module may be a candidate for optionality -when: - - * It does not affect the core syntax of the language. - * It does not significantly affect the output of rendered templates. - * It concerns implementation language features or data types that are not - common to or core in every targeted language. - * The lack of support by an implementation does not diminish the usage of - Mustache in the target language. - -As an example, the lambda module is primarily concerned with the handling of a -particular data type (code). This is a type of data that may be difficult to -support in some languages, and users of those languages will not see the lack -as an 'inconsistency' between implementations. - -Support for specific pragmas or syntax extensions, however, are best managed -outside this core specification, as adjunct specifications. - -Implementors are strongly encouraged to support any and all modules they are -reasonably capable of supporting. diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/Rakefile b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/Rakefile deleted file mode 100644 index 5254ce6..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/Rakefile +++ /dev/null @@ -1,27 +0,0 @@ -require 'json' -require 'yaml' - -# Our custom YAML tags must retain their magic. -%w[ code ].each do |tag| - YAML::add_builtin_type(tag) { |_,val| val.merge(:__tag__ => tag) } -end - -desc 'Build all alternate versions of the specs.' -multitask :build => [ 'build:json' ] - -namespace :build do - note = 'Do not edit this file; changes belong in the appropriate YAML file.' - - desc 'Build JSON versions of the specs.' - task :json do - rm(Dir['specs/*.json'], :verbose => false) - Dir.glob('specs/*.yml').each do |filename| - json_file = filename.gsub('.yml', '.json') - - File.open(json_file, 'w') do |file| - doc = YAML.load_file(filename) - file << doc.merge(:__ATTN__ => note).to_json() - end - end - end -end diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/TESTING.md b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/TESTING.md deleted file mode 100644 index d2ca374..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/TESTING.md +++ /dev/null @@ -1,46 +0,0 @@ -Testing your Mustache implementation against this specification should be -relatively simple. If you have a readily available testing framework on your -platform, your task may be even simpler. - -In general, the process for each `.yml` file is as follows: - -1. Use a YAML parser to load the file. - -2. For each test in the 'tests' array: - - 1. Ensure that each element of the 'partials' hash (if it exists) is - stored in a place where the interpreter will look for it. - - 2. If your implementation will not support lambdas, feel free to skip over - the optional '~lambdas.yml' file. - - 2.1. If your implementation will support lambdas, ensure that each member of - 'data' tagged with '!code' is properly processed into a language- - specific lambda reference. - - * e.g. Given this YAML data hash: - - `{ x: !code { ruby: 'proc { "x" }', perl: 'sub { "x" }' } }` - - a Ruby-based Mustache implementation would process it such that it - was equivalent to this Ruby hash: - - `{ 'x' => proc { "x" } }` - - * If your implementation language does not currently have lambda - examples in the spec, feel free to implement them and send a pull - request. - - * The JSON version of the spec represents these tagged values as a hash - with a '`__tag__`' key of 'code'. - - 3. Render the template (stored in the 'template' key) with the given 'data' - hash. - - 4. Compare the results of your rendering against the 'expected' value; any - differences should be reported, along with any useful debugging - information. - - * Of note, the 'desc' key contains a rough one-line description of the - behavior being tested -- this is most useful in conjunction with the - file name and test 'name'. diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/comments.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/comments.json deleted file mode 100644 index 30cb927..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/comments.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Comment tags represent content that should never appear in the resulting\noutput.\n\nThe tag's content may contain any substring (including newlines) EXCEPT the\nclosing delimiter.\n\nComment tags SHOULD be treated as standalone when appropriate.\n","tests":[{"name":"Inline","data":{},"expected":"1234567890","template":"12345{{! Comment Block! }}67890","desc":"Comment blocks should be removed from the template."},{"name":"Multiline","data":{},"expected":"1234567890\n","template":"12345{{!\n This is a\n multi-line comment...\n}}67890\n","desc":"Multiline comments should be permitted."},{"name":"Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{! Comment Block! }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{! Indented Comment Block! }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n|","template":"|\r\n{{! Standalone Comment }}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{},"expected":"!","template":" {{! I'm Still Standalone }}\n!","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{},"expected":"!\n","template":"!\n {{! I'm Still Standalone }}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Multiline Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Multiline Standalone","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{!\n Something's going on here...\n }}\nEnd.\n","desc":"All standalone comment lines should be removed."},{"name":"Indented Inline","data":{},"expected":" 12 \n","template":" 12 {{! 34 }}\n","desc":"Inline comments should not strip whitespace"},{"name":"Surrounding Whitespace","data":{},"expected":"12345 67890","template":"12345 {{! Comment Block! }} 67890","desc":"Comment removal should preserve surrounding whitespace."}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/comments.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/comments.yml deleted file mode 100644 index 7b14c7f..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/comments.yml +++ /dev/null @@ -1,103 +0,0 @@ -overview: | - Comment tags represent content that should never appear in the resulting - output. - - The tag's content may contain any substring (including newlines) EXCEPT the - closing delimiter. - - Comment tags SHOULD be treated as standalone when appropriate. -tests: - - name: Inline - desc: Comment blocks should be removed from the template. - data: { } - template: '12345{{! Comment Block! }}67890' - expected: '1234567890' - - - name: Multiline - desc: Multiline comments should be permitted. - data: { } - template: | - 12345{{! - This is a - multi-line comment... - }}67890 - expected: | - 1234567890 - - - name: Standalone - desc: All standalone comment lines should be removed. - data: { } - template: | - Begin. - {{! Comment Block! }} - End. - expected: | - Begin. - End. - - - name: Indented Standalone - desc: All standalone comment lines should be removed. - data: { } - template: | - Begin. - {{! Indented Comment Block! }} - End. - expected: | - Begin. - End. - - - name: Standalone Line Endings - desc: '"\r\n" should be considered a newline for standalone tags.' - data: { } - template: "|\r\n{{! Standalone Comment }}\r\n|" - expected: "|\r\n|" - - - name: Standalone Without Previous Line - desc: Standalone tags should not require a newline to precede them. - data: { } - template: " {{! I'm Still Standalone }}\n!" - expected: "!" - - - name: Standalone Without Newline - desc: Standalone tags should not require a newline to follow them. - data: { } - template: "!\n {{! I'm Still Standalone }}" - expected: "!\n" - - - name: Multiline Standalone - desc: All standalone comment lines should be removed. - data: { } - template: | - Begin. - {{! - Something's going on here... - }} - End. - expected: | - Begin. - End. - - - name: Indented Multiline Standalone - desc: All standalone comment lines should be removed. - data: { } - template: | - Begin. - {{! - Something's going on here... - }} - End. - expected: | - Begin. - End. - - - name: Indented Inline - desc: Inline comments should not strip whitespace - data: { } - template: " 12 {{! 34 }}\n" - expected: " 12 \n" - - - name: Surrounding Whitespace - desc: Comment removal should preserve surrounding whitespace. - data: { } - template: '12345 {{! Comment Block! }} 67890' - expected: '12345 67890' diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/delimiters.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/delimiters.json deleted file mode 100644 index fcf9588..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/delimiters.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Set Delimiter tags are used to change the tag delimiters for all content\nfollowing the tag in the current compilation unit.\n\nThe tag's content MUST be any two non-whitespace sequences (separated by\nwhitespace) EXCEPT an equals sign ('=') followed by the current closing\ndelimiter.\n\nSet Delimiter tags SHOULD be treated as standalone when appropriate.\n","tests":[{"name":"Pair Behavior","data":{"text":"Hey!"},"expected":"(Hey!)","template":"{{=<% %>=}}(<%text%>)","desc":"The equals sign (used on both sides) should permit delimiter changes."},{"name":"Special Characters","data":{"text":"It worked!"},"expected":"(It worked!)","template":"({{=[ ]=}}[text])","desc":"Characters with special meaning regexen should be valid delimiters."},{"name":"Sections","data":{"section":true,"data":"I got interpolated."},"expected":"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n","template":"[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n","desc":"Delimiters set outside sections should persist."},{"name":"Inverted Sections","data":{"section":false,"data":"I got interpolated."},"expected":"[\n I got interpolated.\n |data|\n\n {{data}}\n I got interpolated.\n]\n","template":"[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= | | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n","desc":"Delimiters set outside inverted sections should persist."},{"name":"Partial Inheritence","data":{"value":"yes"},"expected":"[ .yes. ]\n[ .yes. ]\n","template":"[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n","desc":"Delimiters set in a parent template should not affect a partial.","partials":{"include":".{{value}}."}},{"name":"Post-Partial Behavior","data":{"value":"yes"},"expected":"[ .yes. .yes. ]\n[ .yes. .|value|. ]\n","template":"[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n","desc":"Delimiters set in a partial should not affect the parent template.","partials":{"include":".{{value}}. {{= | | =}} .|value|."}},{"name":"Surrounding Whitespace","data":{},"expected":"| |","template":"| {{=@ @=}} |","desc":"Surrounding whitespace should be left untouched."},{"name":"Outlying Whitespace (Inline)","data":{},"expected":" | \n","template":" | {{=@ @=}}\n","desc":"Whitespace should be left untouched."},{"name":"Standalone Tag","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n{{=@ @=}}\nEnd.\n","desc":"Standalone lines should be removed from the template."},{"name":"Indented Standalone Tag","data":{},"expected":"Begin.\nEnd.\n","template":"Begin.\n {{=@ @=}}\nEnd.\n","desc":"Indented standalone lines should be removed from the template."},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n|","template":"|\r\n{{= @ @ =}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{},"expected":"=","template":" {{=@ @=}}\n=","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{},"expected":"=\n","template":"=\n {{=@ @=}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Pair with Padding","data":{},"expected":"||","template":"|{{= @ @ =}}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/delimiters.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/delimiters.yml deleted file mode 100644 index ce80b17..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/delimiters.yml +++ /dev/null @@ -1,158 +0,0 @@ -overview: | - Set Delimiter tags are used to change the tag delimiters for all content - following the tag in the current compilation unit. - - The tag's content MUST be any two non-whitespace sequences (separated by - whitespace) EXCEPT an equals sign ('=') followed by the current closing - delimiter. - - Set Delimiter tags SHOULD be treated as standalone when appropriate. -tests: - - name: Pair Behavior - desc: The equals sign (used on both sides) should permit delimiter changes. - data: { text: 'Hey!' } - template: '{{=<% %>=}}(<%text%>)' - expected: '(Hey!)' - - - name: Special Characters - desc: Characters with special meaning regexen should be valid delimiters. - data: { text: 'It worked!' } - template: '({{=[ ]=}}[text])' - expected: '(It worked!)' - - - name: Sections - desc: Delimiters set outside sections should persist. - data: { section: true, data: 'I got interpolated.' } - template: | - [ - {{#section}} - {{data}} - |data| - {{/section}} - - {{= | | =}} - |#section| - {{data}} - |data| - |/section| - ] - expected: | - [ - I got interpolated. - |data| - - {{data}} - I got interpolated. - ] - - - name: Inverted Sections - desc: Delimiters set outside inverted sections should persist. - data: { section: false, data: 'I got interpolated.' } - template: | - [ - {{^section}} - {{data}} - |data| - {{/section}} - - {{= | | =}} - |^section| - {{data}} - |data| - |/section| - ] - expected: | - [ - I got interpolated. - |data| - - {{data}} - I got interpolated. - ] - - - name: Partial Inheritence - desc: Delimiters set in a parent template should not affect a partial. - data: { value: 'yes' } - partials: - include: '.{{value}}.' - template: | - [ {{>include}} ] - {{= | | =}} - [ |>include| ] - expected: | - [ .yes. ] - [ .yes. ] - - - name: Post-Partial Behavior - desc: Delimiters set in a partial should not affect the parent template. - data: { value: 'yes' } - partials: - include: '.{{value}}. {{= | | =}} .|value|.' - template: | - [ {{>include}} ] - [ .{{value}}. .|value|. ] - expected: | - [ .yes. .yes. ] - [ .yes. .|value|. ] - - # Whitespace Sensitivity - - - name: Surrounding Whitespace - desc: Surrounding whitespace should be left untouched. - data: { } - template: '| {{=@ @=}} |' - expected: '| |' - - - name: Outlying Whitespace (Inline) - desc: Whitespace should be left untouched. - data: { } - template: " | {{=@ @=}}\n" - expected: " | \n" - - - name: Standalone Tag - desc: Standalone lines should be removed from the template. - data: { } - template: | - Begin. - {{=@ @=}} - End. - expected: | - Begin. - End. - - - name: Indented Standalone Tag - desc: Indented standalone lines should be removed from the template. - data: { } - template: | - Begin. - {{=@ @=}} - End. - expected: | - Begin. - End. - - - name: Standalone Line Endings - desc: '"\r\n" should be considered a newline for standalone tags.' - data: { } - template: "|\r\n{{= @ @ =}}\r\n|" - expected: "|\r\n|" - - - name: Standalone Without Previous Line - desc: Standalone tags should not require a newline to precede them. - data: { } - template: " {{=@ @=}}\n=" - expected: "=" - - - name: Standalone Without Newline - desc: Standalone tags should not require a newline to follow them. - data: { } - template: "=\n {{=@ @=}}" - expected: "=\n" - - # Whitespace Insensitivity - - - name: Pair with Padding - desc: Superfluous in-tag whitespace should be ignored. - data: { } - template: '|{{= @ @ =}}|' - expected: '||' diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/interpolation.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/interpolation.json deleted file mode 100644 index d1a1a32..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/interpolation.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Interpolation tags are used to integrate dynamic content into the template.\n\nThe tag's content MUST be a non-whitespace character sequence NOT containing\nthe current closing delimiter.\n\nThis tag's content names the data to replace the tag. A single period (`.`)\nindicates that the item currently sitting atop the context stack should be\nused; otherwise, name resolution is as follows:\n 1) Split the name on periods; the first part is the name to resolve, any\n remaining parts should be retained.\n 2) Walk the context stack from top to bottom, finding the first context\n that is a) a hash containing the name as a key OR b) an object responding\n to a method with the given name.\n 3) If the context is a hash, the data is the value associated with the\n name.\n 4) If the context is an object, the data is the value returned by the\n method with the given name.\n 5) If any name parts were retained in step 1, each should be resolved\n against a context stack containing only the result from the former\n resolution. If any part fails resolution, the result should be considered\n falsey, and should interpolate as the empty string.\nData should be coerced into a string (and escaped, if appropriate) before\ninterpolation.\n\nThe Interpolation tags MUST NOT be treated as standalone.\n","tests":[{"name":"No Interpolation","data":{},"expected":"Hello from {Mustache}!\n","template":"Hello from {Mustache}!\n","desc":"Mustache-free templates should render as-is."},{"name":"Basic Interpolation","data":{"subject":"world"},"expected":"Hello, world!\n","template":"Hello, {{subject}}!\n","desc":"Unadorned tags should interpolate content into the template."},{"name":"HTML Escaping","data":{"forbidden":"& \" < >"},"expected":"These characters should be HTML escaped: & " < >\n","template":"These characters should be HTML escaped: {{forbidden}}\n","desc":"Basic interpolation should be HTML escaped."},{"name":"Triple Mustache","data":{"forbidden":"& \" < >"},"expected":"These characters should not be HTML escaped: & \" < >\n","template":"These characters should not be HTML escaped: {{{forbidden}}}\n","desc":"Triple mustaches should interpolate without HTML escaping."},{"name":"Ampersand","data":{"forbidden":"& \" < >"},"expected":"These characters should not be HTML escaped: & \" < >\n","template":"These characters should not be HTML escaped: {{&forbidden}}\n","desc":"Ampersand should interpolate without HTML escaping."},{"name":"Basic Integer Interpolation","data":{"mph":85},"expected":"\"85 miles an hour!\"","template":"\"{{mph}} miles an hour!\"","desc":"Integers should interpolate seamlessly."},{"name":"Triple Mustache Integer Interpolation","data":{"mph":85},"expected":"\"85 miles an hour!\"","template":"\"{{{mph}}} miles an hour!\"","desc":"Integers should interpolate seamlessly."},{"name":"Ampersand Integer Interpolation","data":{"mph":85},"expected":"\"85 miles an hour!\"","template":"\"{{&mph}} miles an hour!\"","desc":"Integers should interpolate seamlessly."},{"name":"Basic Decimal Interpolation","data":{"power":1.21},"expected":"\"1.21 jiggawatts!\"","template":"\"{{power}} jiggawatts!\"","desc":"Decimals should interpolate seamlessly with proper significance."},{"name":"Triple Mustache Decimal Interpolation","data":{"power":1.21},"expected":"\"1.21 jiggawatts!\"","template":"\"{{{power}}} jiggawatts!\"","desc":"Decimals should interpolate seamlessly with proper significance."},{"name":"Ampersand Decimal Interpolation","data":{"power":1.21},"expected":"\"1.21 jiggawatts!\"","template":"\"{{&power}} jiggawatts!\"","desc":"Decimals should interpolate seamlessly with proper significance."},{"name":"Basic Context Miss Interpolation","data":{},"expected":"I () be seen!","template":"I ({{cannot}}) be seen!","desc":"Failed context lookups should default to empty strings."},{"name":"Triple Mustache Context Miss Interpolation","data":{},"expected":"I () be seen!","template":"I ({{{cannot}}}) be seen!","desc":"Failed context lookups should default to empty strings."},{"name":"Ampersand Context Miss Interpolation","data":{},"expected":"I () be seen!","template":"I ({{&cannot}}) be seen!","desc":"Failed context lookups should default to empty strings."},{"name":"Dotted Names - Basic Interpolation","data":{"person":{"name":"Joe"}},"expected":"\"Joe\" == \"Joe\"","template":"\"{{person.name}}\" == \"{{#person}}{{name}}{{/person}}\"","desc":"Dotted names should be considered a form of shorthand for sections."},{"name":"Dotted Names - Triple Mustache Interpolation","data":{"person":{"name":"Joe"}},"expected":"\"Joe\" == \"Joe\"","template":"\"{{{person.name}}}\" == \"{{#person}}{{{name}}}{{/person}}\"","desc":"Dotted names should be considered a form of shorthand for sections."},{"name":"Dotted Names - Ampersand Interpolation","data":{"person":{"name":"Joe"}},"expected":"\"Joe\" == \"Joe\"","template":"\"{{&person.name}}\" == \"{{#person}}{{&name}}{{/person}}\"","desc":"Dotted names should be considered a form of shorthand for sections."},{"name":"Dotted Names - Arbitrary Depth","data":{"a":{"b":{"c":{"d":{"e":{"name":"Phil"}}}}}},"expected":"\"Phil\" == \"Phil\"","template":"\"{{a.b.c.d.e.name}}\" == \"Phil\"","desc":"Dotted names should be functional to any level of nesting."},{"name":"Dotted Names - Broken Chains","data":{"a":{}},"expected":"\"\" == \"\"","template":"\"{{a.b.c}}\" == \"\"","desc":"Any falsey value prior to the last part of the name should yield ''."},{"name":"Dotted Names - Broken Chain Resolution","data":{"a":{"b":{}},"c":{"name":"Jim"}},"expected":"\"\" == \"\"","template":"\"{{a.b.c.name}}\" == \"\"","desc":"Each part of a dotted name should resolve only against its parent."},{"name":"Dotted Names - Initial Resolution","data":{"a":{"b":{"c":{"d":{"e":{"name":"Phil"}}}}},"b":{"c":{"d":{"e":{"name":"Wrong"}}}}},"expected":"\"Phil\" == \"Phil\"","template":"\"{{#a}}{{b.c.d.e.name}}{{/a}}\" == \"Phil\"","desc":"The first part of a dotted name should resolve as any other name."},{"name":"Interpolation - Surrounding Whitespace","data":{"string":"---"},"expected":"| --- |","template":"| {{string}} |","desc":"Interpolation should not alter surrounding whitespace."},{"name":"Triple Mustache - Surrounding Whitespace","data":{"string":"---"},"expected":"| --- |","template":"| {{{string}}} |","desc":"Interpolation should not alter surrounding whitespace."},{"name":"Ampersand - Surrounding Whitespace","data":{"string":"---"},"expected":"| --- |","template":"| {{&string}} |","desc":"Interpolation should not alter surrounding whitespace."},{"name":"Interpolation - Standalone","data":{"string":"---"},"expected":" ---\n","template":" {{string}}\n","desc":"Standalone interpolation should not alter surrounding whitespace."},{"name":"Triple Mustache - Standalone","data":{"string":"---"},"expected":" ---\n","template":" {{{string}}}\n","desc":"Standalone interpolation should not alter surrounding whitespace."},{"name":"Ampersand - Standalone","data":{"string":"---"},"expected":" ---\n","template":" {{&string}}\n","desc":"Standalone interpolation should not alter surrounding whitespace."},{"name":"Interpolation With Padding","data":{"string":"---"},"expected":"|---|","template":"|{{ string }}|","desc":"Superfluous in-tag whitespace should be ignored."},{"name":"Triple Mustache With Padding","data":{"string":"---"},"expected":"|---|","template":"|{{{ string }}}|","desc":"Superfluous in-tag whitespace should be ignored."},{"name":"Ampersand With Padding","data":{"string":"---"},"expected":"|---|","template":"|{{& string }}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/interpolation.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/interpolation.yml deleted file mode 100644 index 2237b55..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/interpolation.yml +++ /dev/null @@ -1,230 +0,0 @@ -overview: | - Interpolation tags are used to integrate dynamic content into the template. - - The tag's content MUST be a non-whitespace character sequence NOT containing - the current closing delimiter. - - This tag's content names the data to replace the tag. A single period (`.`) - indicates that the item currently sitting atop the context stack should be - used; otherwise, name resolution is as follows: - 1) Split the name on periods; the first part is the name to resolve, any - remaining parts should be retained. - 2) Walk the context stack from top to bottom, finding the first context - that is a) a hash containing the name as a key OR b) an object responding - to a method with the given name. - 3) If the context is a hash, the data is the value associated with the - name. - 4) If the context is an object, the data is the value returned by the - method with the given name. - 5) If any name parts were retained in step 1, each should be resolved - against a context stack containing only the result from the former - resolution. If any part fails resolution, the result should be considered - falsey, and should interpolate as the empty string. - Data should be coerced into a string (and escaped, if appropriate) before - interpolation. - - The Interpolation tags MUST NOT be treated as standalone. -tests: - - name: No Interpolation - desc: Mustache-free templates should render as-is. - data: { } - template: | - Hello from {Mustache}! - expected: | - Hello from {Mustache}! - - - name: Basic Interpolation - desc: Unadorned tags should interpolate content into the template. - data: { subject: "world" } - template: | - Hello, {{subject}}! - expected: | - Hello, world! - - - name: HTML Escaping - desc: Basic interpolation should be HTML escaped. - data: { forbidden: '& " < >' } - template: | - These characters should be HTML escaped: {{forbidden}} - expected: | - These characters should be HTML escaped: & " < > - - - name: Triple Mustache - desc: Triple mustaches should interpolate without HTML escaping. - data: { forbidden: '& " < >' } - template: | - These characters should not be HTML escaped: {{{forbidden}}} - expected: | - These characters should not be HTML escaped: & " < > - - - name: Ampersand - desc: Ampersand should interpolate without HTML escaping. - data: { forbidden: '& " < >' } - template: | - These characters should not be HTML escaped: {{&forbidden}} - expected: | - These characters should not be HTML escaped: & " < > - - - name: Basic Integer Interpolation - desc: Integers should interpolate seamlessly. - data: { mph: 85 } - template: '"{{mph}} miles an hour!"' - expected: '"85 miles an hour!"' - - - name: Triple Mustache Integer Interpolation - desc: Integers should interpolate seamlessly. - data: { mph: 85 } - template: '"{{{mph}}} miles an hour!"' - expected: '"85 miles an hour!"' - - - name: Ampersand Integer Interpolation - desc: Integers should interpolate seamlessly. - data: { mph: 85 } - template: '"{{&mph}} miles an hour!"' - expected: '"85 miles an hour!"' - - - name: Basic Decimal Interpolation - desc: Decimals should interpolate seamlessly with proper significance. - data: { power: 1.210 } - template: '"{{power}} jiggawatts!"' - expected: '"1.21 jiggawatts!"' - - - name: Triple Mustache Decimal Interpolation - desc: Decimals should interpolate seamlessly with proper significance. - data: { power: 1.210 } - template: '"{{{power}}} jiggawatts!"' - expected: '"1.21 jiggawatts!"' - - - name: Ampersand Decimal Interpolation - desc: Decimals should interpolate seamlessly with proper significance. - data: { power: 1.210 } - template: '"{{&power}} jiggawatts!"' - expected: '"1.21 jiggawatts!"' - - # Context Misses - - - name: Basic Context Miss Interpolation - desc: Failed context lookups should default to empty strings. - data: { } - template: "I ({{cannot}}) be seen!" - expected: "I () be seen!" - - - name: Triple Mustache Context Miss Interpolation - desc: Failed context lookups should default to empty strings. - data: { } - template: "I ({{{cannot}}}) be seen!" - expected: "I () be seen!" - - - name: Ampersand Context Miss Interpolation - desc: Failed context lookups should default to empty strings. - data: { } - template: "I ({{&cannot}}) be seen!" - expected: "I () be seen!" - - # Dotted Names - - - name: Dotted Names - Basic Interpolation - desc: Dotted names should be considered a form of shorthand for sections. - data: { person: { name: 'Joe' } } - template: '"{{person.name}}" == "{{#person}}{{name}}{{/person}}"' - expected: '"Joe" == "Joe"' - - - name: Dotted Names - Triple Mustache Interpolation - desc: Dotted names should be considered a form of shorthand for sections. - data: { person: { name: 'Joe' } } - template: '"{{{person.name}}}" == "{{#person}}{{{name}}}{{/person}}"' - expected: '"Joe" == "Joe"' - - - name: Dotted Names - Ampersand Interpolation - desc: Dotted names should be considered a form of shorthand for sections. - data: { person: { name: 'Joe' } } - template: '"{{&person.name}}" == "{{#person}}{{&name}}{{/person}}"' - expected: '"Joe" == "Joe"' - - - name: Dotted Names - Arbitrary Depth - desc: Dotted names should be functional to any level of nesting. - data: - a: { b: { c: { d: { e: { name: 'Phil' } } } } } - template: '"{{a.b.c.d.e.name}}" == "Phil"' - expected: '"Phil" == "Phil"' - - - name: Dotted Names - Broken Chains - desc: Any falsey value prior to the last part of the name should yield ''. - data: - a: { } - template: '"{{a.b.c}}" == ""' - expected: '"" == ""' - - - name: Dotted Names - Broken Chain Resolution - desc: Each part of a dotted name should resolve only against its parent. - data: - a: { b: { } } - c: { name: 'Jim' } - template: '"{{a.b.c.name}}" == ""' - expected: '"" == ""' - - - name: Dotted Names - Initial Resolution - desc: The first part of a dotted name should resolve as any other name. - data: - a: { b: { c: { d: { e: { name: 'Phil' } } } } } - b: { c: { d: { e: { name: 'Wrong' } } } } - template: '"{{#a}}{{b.c.d.e.name}}{{/a}}" == "Phil"' - expected: '"Phil" == "Phil"' - - # Whitespace Sensitivity - - - name: Interpolation - Surrounding Whitespace - desc: Interpolation should not alter surrounding whitespace. - data: { string: '---' } - template: '| {{string}} |' - expected: '| --- |' - - - name: Triple Mustache - Surrounding Whitespace - desc: Interpolation should not alter surrounding whitespace. - data: { string: '---' } - template: '| {{{string}}} |' - expected: '| --- |' - - - name: Ampersand - Surrounding Whitespace - desc: Interpolation should not alter surrounding whitespace. - data: { string: '---' } - template: '| {{&string}} |' - expected: '| --- |' - - - name: Interpolation - Standalone - desc: Standalone interpolation should not alter surrounding whitespace. - data: { string: '---' } - template: " {{string}}\n" - expected: " ---\n" - - - name: Triple Mustache - Standalone - desc: Standalone interpolation should not alter surrounding whitespace. - data: { string: '---' } - template: " {{{string}}}\n" - expected: " ---\n" - - - name: Ampersand - Standalone - desc: Standalone interpolation should not alter surrounding whitespace. - data: { string: '---' } - template: " {{&string}}\n" - expected: " ---\n" - - # Whitespace Insensitivity - - - name: Interpolation With Padding - desc: Superfluous in-tag whitespace should be ignored. - data: { string: "---" } - template: '|{{ string }}|' - expected: '|---|' - - - name: Triple Mustache With Padding - desc: Superfluous in-tag whitespace should be ignored. - data: { string: "---" } - template: '|{{{ string }}}|' - expected: '|---|' - - - name: Ampersand With Padding - desc: Superfluous in-tag whitespace should be ignored. - data: { string: "---" } - template: '|{{& string }}|' - expected: '|---|' diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/inverted.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/inverted.json deleted file mode 100644 index c9b550b..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/inverted.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Inverted Section tags and End Section tags are used in combination to wrap a\nsection of the template.\n\nThese tags' content MUST be a non-whitespace character sequence NOT\ncontaining the current closing delimiter; each Inverted Section tag MUST be\nfollowed by an End Section tag with the same content within the same\nsection.\n\nThis tag's content names the data to replace the tag. Name resolution is as\nfollows:\n 1) Split the name on periods; the first part is the name to resolve, any\n remaining parts should be retained.\n 2) Walk the context stack from top to bottom, finding the first context\n that is a) a hash containing the name as a key OR b) an object responding\n to a method with the given name.\n 3) If the context is a hash, the data is the value associated with the\n name.\n 4) If the context is an object and the method with the given name has an\n arity of 1, the method SHOULD be called with a String containing the\n unprocessed contents of the sections; the data is the value returned.\n 5) Otherwise, the data is the value returned by calling the method with\n the given name.\n 6) If any name parts were retained in step 1, each should be resolved\n against a context stack containing only the result from the former\n resolution. If any part fails resolution, the result should be considered\n falsey, and should interpolate as the empty string.\nIf the data is not of a list type, it is coerced into a list as follows: if\nthe data is truthy (e.g. `!!data == true`), use a single-element list\ncontaining the data, otherwise use an empty list.\n\nThis section MUST NOT be rendered unless the data list is empty.\n\nInverted Section and End Section tags SHOULD be treated as standalone when\nappropriate.\n","tests":[{"name":"Falsey","data":{"boolean":false},"expected":"\"This should be rendered.\"","template":"\"{{^boolean}}This should be rendered.{{/boolean}}\"","desc":"Falsey sections should have their contents rendered."},{"name":"Truthy","data":{"boolean":true},"expected":"\"\"","template":"\"{{^boolean}}This should not be rendered.{{/boolean}}\"","desc":"Truthy sections should have their contents omitted."},{"name":"Context","data":{"context":{"name":"Joe"}},"expected":"\"\"","template":"\"{{^context}}Hi {{name}}.{{/context}}\"","desc":"Objects and hashes should behave like truthy values."},{"name":"List","data":{"list":[{"n":1},{"n":2},{"n":3}]},"expected":"\"\"","template":"\"{{^list}}{{n}}{{/list}}\"","desc":"Lists should behave like truthy values."},{"name":"Empty List","data":{"list":[]},"expected":"\"Yay lists!\"","template":"\"{{^list}}Yay lists!{{/list}}\"","desc":"Empty lists should behave like falsey values."},{"name":"Doubled","data":{"two":"second","bool":false},"expected":"* first\n* second\n* third\n","template":"{{^bool}}\n* first\n{{/bool}}\n* {{two}}\n{{^bool}}\n* third\n{{/bool}}\n","desc":"Multiple inverted sections per template should be permitted."},{"name":"Nested (Falsey)","data":{"bool":false},"expected":"| A B C D E |","template":"| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested falsey sections should have their contents rendered."},{"name":"Nested (Truthy)","data":{"bool":true},"expected":"| A E |","template":"| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested truthy sections should be omitted."},{"name":"Context Misses","data":{},"expected":"[Cannot find key 'missing'!]","template":"[{{^missing}}Cannot find key 'missing'!{{/missing}}]","desc":"Failed context lookups should be considered falsey."},{"name":"Dotted Names - Truthy","data":{"a":{"b":{"c":true}}},"expected":"\"\" == \"\"","template":"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"\"","desc":"Dotted names should be valid for Inverted Section tags."},{"name":"Dotted Names - Falsey","data":{"a":{"b":{"c":false}}},"expected":"\"Not Here\" == \"Not Here\"","template":"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\"","desc":"Dotted names should be valid for Inverted Section tags."},{"name":"Dotted Names - Broken Chains","data":{"a":{}},"expected":"\"Not Here\" == \"Not Here\"","template":"\"{{^a.b.c}}Not Here{{/a.b.c}}\" == \"Not Here\"","desc":"Dotted names that cannot be resolved should be considered falsey."},{"name":"Surrounding Whitespace","data":{"boolean":false},"expected":" | \t|\t | \n","template":" | {{^boolean}}\t|\t{{/boolean}} | \n","desc":"Inverted sections should not alter surrounding whitespace."},{"name":"Internal Whitespace","data":{"boolean":false},"expected":" | \n | \n","template":" | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n","desc":"Inverted should not alter internal whitespace."},{"name":"Indented Inline Sections","data":{"boolean":false},"expected":" NO\n WAY\n","template":" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n","desc":"Single-line sections should not alter surrounding whitespace."},{"name":"Standalone Lines","data":{"boolean":false},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n","desc":"Standalone lines should be removed from the template."},{"name":"Standalone Indented Lines","data":{"boolean":false},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n {{^boolean}}\n|\n {{/boolean}}\n| A Line\n","desc":"Standalone indented lines should be removed from the template."},{"name":"Standalone Line Endings","data":{"boolean":false},"expected":"|\r\n|","template":"|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{"boolean":false},"expected":"^\n/","template":" {{^boolean}}\n^{{/boolean}}\n/","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{"boolean":false},"expected":"^\n/\n","template":"^{{^boolean}}\n/\n {{/boolean}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Padding","data":{"boolean":false},"expected":"|=|","template":"|{{^ boolean }}={{/ boolean }}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/inverted.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/inverted.yml deleted file mode 100644 index 5f8e2b2..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/inverted.yml +++ /dev/null @@ -1,193 +0,0 @@ -overview: | - Inverted Section tags and End Section tags are used in combination to wrap a - section of the template. - - These tags' content MUST be a non-whitespace character sequence NOT - containing the current closing delimiter; each Inverted Section tag MUST be - followed by an End Section tag with the same content within the same - section. - - This tag's content names the data to replace the tag. Name resolution is as - follows: - 1) Split the name on periods; the first part is the name to resolve, any - remaining parts should be retained. - 2) Walk the context stack from top to bottom, finding the first context - that is a) a hash containing the name as a key OR b) an object responding - to a method with the given name. - 3) If the context is a hash, the data is the value associated with the - name. - 4) If the context is an object and the method with the given name has an - arity of 1, the method SHOULD be called with a String containing the - unprocessed contents of the sections; the data is the value returned. - 5) Otherwise, the data is the value returned by calling the method with - the given name. - 6) If any name parts were retained in step 1, each should be resolved - against a context stack containing only the result from the former - resolution. If any part fails resolution, the result should be considered - falsey, and should interpolate as the empty string. - If the data is not of a list type, it is coerced into a list as follows: if - the data is truthy (e.g. `!!data == true`), use a single-element list - containing the data, otherwise use an empty list. - - This section MUST NOT be rendered unless the data list is empty. - - Inverted Section and End Section tags SHOULD be treated as standalone when - appropriate. -tests: - - name: Falsey - desc: Falsey sections should have their contents rendered. - data: { boolean: false } - template: '"{{^boolean}}This should be rendered.{{/boolean}}"' - expected: '"This should be rendered."' - - - name: Truthy - desc: Truthy sections should have their contents omitted. - data: { boolean: true } - template: '"{{^boolean}}This should not be rendered.{{/boolean}}"' - expected: '""' - - - name: Context - desc: Objects and hashes should behave like truthy values. - data: { context: { name: 'Joe' } } - template: '"{{^context}}Hi {{name}}.{{/context}}"' - expected: '""' - - - name: List - desc: Lists should behave like truthy values. - data: { list: [ { n: 1 }, { n: 2 }, { n: 3 } ] } - template: '"{{^list}}{{n}}{{/list}}"' - expected: '""' - - - name: Empty List - desc: Empty lists should behave like falsey values. - data: { list: [ ] } - template: '"{{^list}}Yay lists!{{/list}}"' - expected: '"Yay lists!"' - - - name: Doubled - desc: Multiple inverted sections per template should be permitted. - data: { bool: false, two: 'second' } - template: | - {{^bool}} - * first - {{/bool}} - * {{two}} - {{^bool}} - * third - {{/bool}} - expected: | - * first - * second - * third - - - name: Nested (Falsey) - desc: Nested falsey sections should have their contents rendered. - data: { bool: false } - template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |" - expected: "| A B C D E |" - - - name: Nested (Truthy) - desc: Nested truthy sections should be omitted. - data: { bool: true } - template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |" - expected: "| A E |" - - - name: Context Misses - desc: Failed context lookups should be considered falsey. - data: { } - template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]" - expected: "[Cannot find key 'missing'!]" - - # Dotted Names - - - name: Dotted Names - Truthy - desc: Dotted names should be valid for Inverted Section tags. - data: { a: { b: { c: true } } } - template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == ""' - expected: '"" == ""' - - - name: Dotted Names - Falsey - desc: Dotted names should be valid for Inverted Section tags. - data: { a: { b: { c: false } } } - template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"' - expected: '"Not Here" == "Not Here"' - - - name: Dotted Names - Broken Chains - desc: Dotted names that cannot be resolved should be considered falsey. - data: { a: { } } - template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"' - expected: '"Not Here" == "Not Here"' - - # Whitespace Sensitivity - - - name: Surrounding Whitespace - desc: Inverted sections should not alter surrounding whitespace. - data: { boolean: false } - template: " | {{^boolean}}\t|\t{{/boolean}} | \n" - expected: " | \t|\t | \n" - - - name: Internal Whitespace - desc: Inverted should not alter internal whitespace. - data: { boolean: false } - template: " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n" - expected: " | \n | \n" - - - name: Indented Inline Sections - desc: Single-line sections should not alter surrounding whitespace. - data: { boolean: false } - template: " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n" - expected: " NO\n WAY\n" - - - name: Standalone Lines - desc: Standalone lines should be removed from the template. - data: { boolean: false } - template: | - | This Is - {{^boolean}} - | - {{/boolean}} - | A Line - expected: | - | This Is - | - | A Line - - - name: Standalone Indented Lines - desc: Standalone indented lines should be removed from the template. - data: { boolean: false } - template: | - | This Is - {{^boolean}} - | - {{/boolean}} - | A Line - expected: | - | This Is - | - | A Line - - - name: Standalone Line Endings - desc: '"\r\n" should be considered a newline for standalone tags.' - data: { boolean: false } - template: "|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|" - expected: "|\r\n|" - - - name: Standalone Without Previous Line - desc: Standalone tags should not require a newline to precede them. - data: { boolean: false } - template: " {{^boolean}}\n^{{/boolean}}\n/" - expected: "^\n/" - - - name: Standalone Without Newline - desc: Standalone tags should not require a newline to follow them. - data: { boolean: false } - template: "^{{^boolean}}\n/\n {{/boolean}}" - expected: "^\n/\n" - - # Whitespace Insensitivity - - - name: Padding - desc: Superfluous in-tag whitespace should be ignored. - data: { boolean: false } - template: '|{{^ boolean }}={{/ boolean }}|' - expected: '|=|' diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/partials.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/partials.json deleted file mode 100644 index e5f21a2..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/partials.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Partial tags are used to expand an external template into the current\ntemplate.\n\nThe tag's content MUST be a non-whitespace character sequence NOT containing\nthe current closing delimiter.\n\nThis tag's content names the partial to inject. Set Delimiter tags MUST NOT\naffect the parsing of a partial. The partial MUST be rendered against the\ncontext stack local to the tag. If the named partial cannot be found, the\nempty string SHOULD be used instead, as in interpolations.\n\nPartial tags SHOULD be treated as standalone when appropriate. If this tag\nis used standalone, any whitespace preceding the tag should treated as\nindentation, and prepended to each line of the partial before rendering.\n","tests":[{"name":"Basic Behavior","data":{},"expected":"\"from partial\"","template":"\"{{>text}}\"","desc":"The greater-than operator should expand to the named partial.","partials":{"text":"from partial"}},{"name":"Failed Lookup","data":{},"expected":"\"\"","template":"\"{{>text}}\"","desc":"The empty string should be used when the named partial is not found.","partials":{}},{"name":"Context","data":{"text":"content"},"expected":"\"*content*\"","template":"\"{{>partial}}\"","desc":"The greater-than operator should operate within the current context.","partials":{"partial":"*{{text}}*"}},{"name":"Recursion","data":{"content":"X","nodes":[{"content":"Y","nodes":[]}]},"expected":"X>","template":"{{>node}}","desc":"The greater-than operator should properly recurse.","partials":{"node":"{{content}}<{{#nodes}}{{>node}}{{/nodes}}>"}},{"name":"Surrounding Whitespace","data":{},"expected":"| \t|\t |","template":"| {{>partial}} |","desc":"The greater-than operator should not alter surrounding whitespace.","partials":{"partial":"\t|\t"}},{"name":"Inline Indentation","data":{"data":"|"},"expected":" | >\n>\n","template":" {{data}} {{> partial}}\n","desc":"Whitespace should be left untouched.","partials":{"partial":">\n>"}},{"name":"Standalone Line Endings","data":{},"expected":"|\r\n>|","template":"|\r\n{{>partial}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags.","partials":{"partial":">"}},{"name":"Standalone Without Previous Line","data":{},"expected":" >\n >>","template":" {{>partial}}\n>","desc":"Standalone tags should not require a newline to precede them.","partials":{"partial":">\n>"}},{"name":"Standalone Without Newline","data":{},"expected":">\n >\n >","template":">\n {{>partial}}","desc":"Standalone tags should not require a newline to follow them.","partials":{"partial":">\n>"}},{"name":"Standalone Indentation","data":{"content":"<\n->"},"expected":"\\\n |\n <\n->\n |\n/\n","template":"\\\n {{>partial}}\n/\n","desc":"Each line of the partial should be indented before rendering.","partials":{"partial":"|\n{{{content}}}\n|\n"}},{"name":"Padding Whitespace","data":{"boolean":true},"expected":"|[]|","template":"|{{> partial }}|","desc":"Superfluous in-tag whitespace should be ignored.","partials":{"partial":"[]"}}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/partials.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/partials.yml deleted file mode 100644 index 8c41543..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/partials.yml +++ /dev/null @@ -1,109 +0,0 @@ -overview: | - Partial tags are used to expand an external template into the current - template. - - The tag's content MUST be a non-whitespace character sequence NOT containing - the current closing delimiter. - - This tag's content names the partial to inject. Set Delimiter tags MUST NOT - affect the parsing of a partial. The partial MUST be rendered against the - context stack local to the tag. If the named partial cannot be found, the - empty string SHOULD be used instead, as in interpolations. - - Partial tags SHOULD be treated as standalone when appropriate. If this tag - is used standalone, any whitespace preceding the tag should treated as - indentation, and prepended to each line of the partial before rendering. -tests: - - name: Basic Behavior - desc: The greater-than operator should expand to the named partial. - data: { } - template: '"{{>text}}"' - partials: { text: 'from partial' } - expected: '"from partial"' - - - name: Failed Lookup - desc: The empty string should be used when the named partial is not found. - data: { } - template: '"{{>text}}"' - partials: { } - expected: '""' - - - name: Context - desc: The greater-than operator should operate within the current context. - data: { text: 'content' } - template: '"{{>partial}}"' - partials: { partial: '*{{text}}*' } - expected: '"*content*"' - - - name: Recursion - desc: The greater-than operator should properly recurse. - data: { content: "X", nodes: [ { content: "Y", nodes: [] } ] } - template: '{{>node}}' - partials: { node: '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' } - expected: 'X>' - - # Whitespace Sensitivity - - - name: Surrounding Whitespace - desc: The greater-than operator should not alter surrounding whitespace. - data: { } - template: '| {{>partial}} |' - partials: { partial: "\t|\t" } - expected: "| \t|\t |" - - - name: Inline Indentation - desc: Whitespace should be left untouched. - data: { data: '|' } - template: " {{data}} {{> partial}}\n" - partials: { partial: ">\n>" } - expected: " | >\n>\n" - - - name: Standalone Line Endings - desc: '"\r\n" should be considered a newline for standalone tags.' - data: { } - template: "|\r\n{{>partial}}\r\n|" - partials: { partial: ">" } - expected: "|\r\n>|" - - - name: Standalone Without Previous Line - desc: Standalone tags should not require a newline to precede them. - data: { } - template: " {{>partial}}\n>" - partials: { partial: ">\n>"} - expected: " >\n >>" - - - name: Standalone Without Newline - desc: Standalone tags should not require a newline to follow them. - data: { } - template: ">\n {{>partial}}" - partials: { partial: ">\n>" } - expected: ">\n >\n >" - - - name: Standalone Indentation - desc: Each line of the partial should be indented before rendering. - data: { content: "<\n->" } - template: | - \ - {{>partial}} - / - partials: - partial: | - | - {{{content}}} - | - expected: | - \ - | - < - -> - | - / - - # Whitespace Insensitivity - - - name: Padding Whitespace - desc: Superfluous in-tag whitespace should be ignored. - data: { boolean: true } - template: "|{{> partial }}|" - partials: { partial: "[]" } - expected: '|[]|' diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/sections.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/sections.json deleted file mode 100644 index b0aa352..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/sections.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Section tags and End Section tags are used in combination to wrap a section\nof the template for iteration\n\nThese tags' content MUST be a non-whitespace character sequence NOT\ncontaining the current closing delimiter; each Section tag MUST be followed\nby an End Section tag with the same content within the same section.\n\nThis tag's content names the data to replace the tag. Name resolution is as\nfollows:\n 1) Split the name on periods; the first part is the name to resolve, any\n remaining parts should be retained.\n 2) Walk the context stack from top to bottom, finding the first context\n that is a) a hash containing the name as a key OR b) an object responding\n to a method with the given name.\n 3) If the context is a hash, the data is the value associated with the\n name.\n 4) If the context is an object and the method with the given name has an\n arity of 1, the method SHOULD be called with a String containing the\n unprocessed contents of the sections; the data is the value returned.\n 5) Otherwise, the data is the value returned by calling the method with\n the given name.\n 6) If any name parts were retained in step 1, each should be resolved\n against a context stack containing only the result from the former\n resolution. If any part fails resolution, the result should be considered\n falsey, and should interpolate as the empty string.\nIf the data is not of a list type, it is coerced into a list as follows: if\nthe data is truthy (e.g. `!!data == true`), use a single-element list\ncontaining the data, otherwise use an empty list.\n\nFor each element in the data list, the element MUST be pushed onto the\ncontext stack, the section MUST be rendered, and the element MUST be popped\noff the context stack.\n\nSection and End Section tags SHOULD be treated as standalone when\nappropriate.\n","tests":[{"name":"Truthy","data":{"boolean":true},"expected":"\"This should be rendered.\"","template":"\"{{#boolean}}This should be rendered.{{/boolean}}\"","desc":"Truthy sections should have their contents rendered."},{"name":"Falsey","data":{"boolean":false},"expected":"\"\"","template":"\"{{#boolean}}This should not be rendered.{{/boolean}}\"","desc":"Falsey sections should have their contents omitted."},{"name":"Context","data":{"context":{"name":"Joe"}},"expected":"\"Hi Joe.\"","template":"\"{{#context}}Hi {{name}}.{{/context}}\"","desc":"Objects and hashes should be pushed onto the context stack."},{"name":"Deeply Nested Contexts","data":{"a":{"one":1},"b":{"two":2},"c":{"three":3},"d":{"four":4},"e":{"five":5}},"expected":"1\n121\n12321\n1234321\n123454321\n1234321\n12321\n121\n1\n","template":"{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{#e}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}\n{{/e}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{/d}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{/c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n","desc":"All elements on the context stack should be accessible."},{"name":"List","data":{"list":[{"item":1},{"item":2},{"item":3}]},"expected":"\"123\"","template":"\"{{#list}}{{item}}{{/list}}\"","desc":"Lists should be iterated; list items should visit the context stack."},{"name":"Empty List","data":{"list":[]},"expected":"\"\"","template":"\"{{#list}}Yay lists!{{/list}}\"","desc":"Empty lists should behave like falsey values."},{"name":"Doubled","data":{"two":"second","bool":true},"expected":"* first\n* second\n* third\n","template":"{{#bool}}\n* first\n{{/bool}}\n* {{two}}\n{{#bool}}\n* third\n{{/bool}}\n","desc":"Multiple sections per template should be permitted."},{"name":"Nested (Truthy)","data":{"bool":true},"expected":"| A B C D E |","template":"| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested truthy sections should have their contents rendered."},{"name":"Nested (Falsey)","data":{"bool":false},"expected":"| A E |","template":"| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |","desc":"Nested falsey sections should be omitted."},{"name":"Context Misses","data":{},"expected":"[]","template":"[{{#missing}}Found key 'missing'!{{/missing}}]","desc":"Failed context lookups should be considered falsey."},{"name":"Implicit Iterator - String","data":{"list":["a","b","c","d","e"]},"expected":"\"(a)(b)(c)(d)(e)\"","template":"\"{{#list}}({{.}}){{/list}}\"","desc":"Implicit iterators should directly interpolate strings."},{"name":"Implicit Iterator - Integer","data":{"list":[1,2,3,4,5]},"expected":"\"(1)(2)(3)(4)(5)\"","template":"\"{{#list}}({{.}}){{/list}}\"","desc":"Implicit iterators should cast integers to strings and interpolate."},{"name":"Implicit Iterator - Decimal","data":{"list":[1.1,2.2,3.3,4.4,5.5]},"expected":"\"(1.1)(2.2)(3.3)(4.4)(5.5)\"","template":"\"{{#list}}({{.}}){{/list}}\"","desc":"Implicit iterators should cast decimals to strings and interpolate."},{"name":"Dotted Names - Truthy","data":{"a":{"b":{"c":true}}},"expected":"\"Here\" == \"Here\"","template":"\"{{#a.b.c}}Here{{/a.b.c}}\" == \"Here\"","desc":"Dotted names should be valid for Section tags."},{"name":"Dotted Names - Falsey","data":{"a":{"b":{"c":false}}},"expected":"\"\" == \"\"","template":"\"{{#a.b.c}}Here{{/a.b.c}}\" == \"\"","desc":"Dotted names should be valid for Section tags."},{"name":"Dotted Names - Broken Chains","data":{"a":{}},"expected":"\"\" == \"\"","template":"\"{{#a.b.c}}Here{{/a.b.c}}\" == \"\"","desc":"Dotted names that cannot be resolved should be considered falsey."},{"name":"Surrounding Whitespace","data":{"boolean":true},"expected":" | \t|\t | \n","template":" | {{#boolean}}\t|\t{{/boolean}} | \n","desc":"Sections should not alter surrounding whitespace."},{"name":"Internal Whitespace","data":{"boolean":true},"expected":" | \n | \n","template":" | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n","desc":"Sections should not alter internal whitespace."},{"name":"Indented Inline Sections","data":{"boolean":true},"expected":" YES\n GOOD\n","template":" {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n","desc":"Single-line sections should not alter surrounding whitespace."},{"name":"Standalone Lines","data":{"boolean":true},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n","desc":"Standalone lines should be removed from the template."},{"name":"Indented Standalone Lines","data":{"boolean":true},"expected":"| This Is\n|\n| A Line\n","template":"| This Is\n {{#boolean}}\n|\n {{/boolean}}\n| A Line\n","desc":"Indented standalone lines should be removed from the template."},{"name":"Standalone Line Endings","data":{"boolean":true},"expected":"|\r\n|","template":"|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|","desc":"\"\\r\\n\" should be considered a newline for standalone tags."},{"name":"Standalone Without Previous Line","data":{"boolean":true},"expected":"#\n/","template":" {{#boolean}}\n#{{/boolean}}\n/","desc":"Standalone tags should not require a newline to precede them."},{"name":"Standalone Without Newline","data":{"boolean":true},"expected":"#\n/\n","template":"#{{#boolean}}\n/\n {{/boolean}}","desc":"Standalone tags should not require a newline to follow them."},{"name":"Padding","data":{"boolean":true},"expected":"|=|","template":"|{{# boolean }}={{/ boolean }}|","desc":"Superfluous in-tag whitespace should be ignored."}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/sections.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/sections.yml deleted file mode 100644 index f62d9cb..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/sections.yml +++ /dev/null @@ -1,256 +0,0 @@ -overview: | - Section tags and End Section tags are used in combination to wrap a section - of the template for iteration - - These tags' content MUST be a non-whitespace character sequence NOT - containing the current closing delimiter; each Section tag MUST be followed - by an End Section tag with the same content within the same section. - - This tag's content names the data to replace the tag. Name resolution is as - follows: - 1) Split the name on periods; the first part is the name to resolve, any - remaining parts should be retained. - 2) Walk the context stack from top to bottom, finding the first context - that is a) a hash containing the name as a key OR b) an object responding - to a method with the given name. - 3) If the context is a hash, the data is the value associated with the - name. - 4) If the context is an object and the method with the given name has an - arity of 1, the method SHOULD be called with a String containing the - unprocessed contents of the sections; the data is the value returned. - 5) Otherwise, the data is the value returned by calling the method with - the given name. - 6) If any name parts were retained in step 1, each should be resolved - against a context stack containing only the result from the former - resolution. If any part fails resolution, the result should be considered - falsey, and should interpolate as the empty string. - If the data is not of a list type, it is coerced into a list as follows: if - the data is truthy (e.g. `!!data == true`), use a single-element list - containing the data, otherwise use an empty list. - - For each element in the data list, the element MUST be pushed onto the - context stack, the section MUST be rendered, and the element MUST be popped - off the context stack. - - Section and End Section tags SHOULD be treated as standalone when - appropriate. -tests: - - name: Truthy - desc: Truthy sections should have their contents rendered. - data: { boolean: true } - template: '"{{#boolean}}This should be rendered.{{/boolean}}"' - expected: '"This should be rendered."' - - - name: Falsey - desc: Falsey sections should have their contents omitted. - data: { boolean: false } - template: '"{{#boolean}}This should not be rendered.{{/boolean}}"' - expected: '""' - - - name: Context - desc: Objects and hashes should be pushed onto the context stack. - data: { context: { name: 'Joe' } } - template: '"{{#context}}Hi {{name}}.{{/context}}"' - expected: '"Hi Joe."' - - - name: Deeply Nested Contexts - desc: All elements on the context stack should be accessible. - data: - a: { one: 1 } - b: { two: 2 } - c: { three: 3 } - d: { four: 4 } - e: { five: 5 } - template: | - {{#a}} - {{one}} - {{#b}} - {{one}}{{two}}{{one}} - {{#c}} - {{one}}{{two}}{{three}}{{two}}{{one}} - {{#d}} - {{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}} - {{#e}} - {{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}} - {{/e}} - {{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}} - {{/d}} - {{one}}{{two}}{{three}}{{two}}{{one}} - {{/c}} - {{one}}{{two}}{{one}} - {{/b}} - {{one}} - {{/a}} - expected: | - 1 - 121 - 12321 - 1234321 - 123454321 - 1234321 - 12321 - 121 - 1 - - - name: List - desc: Lists should be iterated; list items should visit the context stack. - data: { list: [ { item: 1 }, { item: 2 }, { item: 3 } ] } - template: '"{{#list}}{{item}}{{/list}}"' - expected: '"123"' - - - name: Empty List - desc: Empty lists should behave like falsey values. - data: { list: [ ] } - template: '"{{#list}}Yay lists!{{/list}}"' - expected: '""' - - - name: Doubled - desc: Multiple sections per template should be permitted. - data: { bool: true, two: 'second' } - template: | - {{#bool}} - * first - {{/bool}} - * {{two}} - {{#bool}} - * third - {{/bool}} - expected: | - * first - * second - * third - - - name: Nested (Truthy) - desc: Nested truthy sections should have their contents rendered. - data: { bool: true } - template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |" - expected: "| A B C D E |" - - - name: Nested (Falsey) - desc: Nested falsey sections should be omitted. - data: { bool: false } - template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |" - expected: "| A E |" - - - name: Context Misses - desc: Failed context lookups should be considered falsey. - data: { } - template: "[{{#missing}}Found key 'missing'!{{/missing}}]" - expected: "[]" - - # Implicit Iterators - - - name: Implicit Iterator - String - desc: Implicit iterators should directly interpolate strings. - data: - list: [ 'a', 'b', 'c', 'd', 'e' ] - template: '"{{#list}}({{.}}){{/list}}"' - expected: '"(a)(b)(c)(d)(e)"' - - - name: Implicit Iterator - Integer - desc: Implicit iterators should cast integers to strings and interpolate. - data: - list: [ 1, 2, 3, 4, 5 ] - template: '"{{#list}}({{.}}){{/list}}"' - expected: '"(1)(2)(3)(4)(5)"' - - - name: Implicit Iterator - Decimal - desc: Implicit iterators should cast decimals to strings and interpolate. - data: - list: [ 1.10, 2.20, 3.30, 4.40, 5.50 ] - template: '"{{#list}}({{.}}){{/list}}"' - expected: '"(1.1)(2.2)(3.3)(4.4)(5.5)"' - - # Dotted Names - - - name: Dotted Names - Truthy - desc: Dotted names should be valid for Section tags. - data: { a: { b: { c: true } } } - template: '"{{#a.b.c}}Here{{/a.b.c}}" == "Here"' - expected: '"Here" == "Here"' - - - name: Dotted Names - Falsey - desc: Dotted names should be valid for Section tags. - data: { a: { b: { c: false } } } - template: '"{{#a.b.c}}Here{{/a.b.c}}" == ""' - expected: '"" == ""' - - - name: Dotted Names - Broken Chains - desc: Dotted names that cannot be resolved should be considered falsey. - data: { a: { } } - template: '"{{#a.b.c}}Here{{/a.b.c}}" == ""' - expected: '"" == ""' - - # Whitespace Sensitivity - - - name: Surrounding Whitespace - desc: Sections should not alter surrounding whitespace. - data: { boolean: true } - template: " | {{#boolean}}\t|\t{{/boolean}} | \n" - expected: " | \t|\t | \n" - - - name: Internal Whitespace - desc: Sections should not alter internal whitespace. - data: { boolean: true } - template: " | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n" - expected: " | \n | \n" - - - name: Indented Inline Sections - desc: Single-line sections should not alter surrounding whitespace. - data: { boolean: true } - template: " {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n" - expected: " YES\n GOOD\n" - - - name: Standalone Lines - desc: Standalone lines should be removed from the template. - data: { boolean: true } - template: | - | This Is - {{#boolean}} - | - {{/boolean}} - | A Line - expected: | - | This Is - | - | A Line - - - name: Indented Standalone Lines - desc: Indented standalone lines should be removed from the template. - data: { boolean: true } - template: | - | This Is - {{#boolean}} - | - {{/boolean}} - | A Line - expected: | - | This Is - | - | A Line - - - name: Standalone Line Endings - desc: '"\r\n" should be considered a newline for standalone tags.' - data: { boolean: true } - template: "|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|" - expected: "|\r\n|" - - - name: Standalone Without Previous Line - desc: Standalone tags should not require a newline to precede them. - data: { boolean: true } - template: " {{#boolean}}\n#{{/boolean}}\n/" - expected: "#\n/" - - - name: Standalone Without Newline - desc: Standalone tags should not require a newline to follow them. - data: { boolean: true } - template: "#{{#boolean}}\n/\n {{/boolean}}" - expected: "#\n/\n" - - # Whitespace Insensitivity - - - name: Padding - desc: Superfluous in-tag whitespace should be ignored. - data: { boolean: true } - template: '|{{# boolean }}={{/ boolean }}|' - expected: '|=|' diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/~lambdas.json b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/~lambdas.json deleted file mode 100644 index 3c58bf8..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/~lambdas.json +++ /dev/null @@ -1 +0,0 @@ -{"__ATTN__":"Do not edit this file; changes belong in the appropriate YAML file.","overview":"Lambdas are a special-cased data type for use in interpolations and\nsections.\n\nWhen used as the data value for an Interpolation tag, the lambda MUST be\ntreatable as an arity 0 function, and invoked as such. The returned value\nMUST be rendered against the default delimiters, then interpolated in place\nof the lambda.\n\nWhen used as the data value for a Section tag, the lambda MUST be treatable\nas an arity 1 function, and invoked as such (passing a String containing the\nunprocessed section contents). The returned value MUST be rendered against\nthe current delimiters, then interpolated in place of the section.\n","tests":[{"name":"Interpolation","data":{"lambda":{"php":"return \"world\";","clojure":"(fn [] \"world\")","__tag__":"code","perl":"sub { \"world\" }","python":"lambda: \"world\"","ruby":"proc { \"world\" }","js":"function() { return \"world\" }"}},"expected":"Hello, world!","template":"Hello, {{lambda}}!","desc":"A lambda's return value should be interpolated."},{"name":"Interpolation - Expansion","data":{"planet":"world","lambda":{"php":"return \"{{planet}}\";","clojure":"(fn [] \"{{planet}}\")","__tag__":"code","perl":"sub { \"{{planet}}\" }","python":"lambda: \"{{planet}}\"","ruby":"proc { \"{{planet}}\" }","js":"function() { return \"{{planet}}\" }"}},"expected":"Hello, world!","template":"Hello, {{lambda}}!","desc":"A lambda's return value should be parsed."},{"name":"Interpolation - Alternate Delimiters","data":{"planet":"world","lambda":{"php":"return \"|planet| => {{planet}}\";","clojure":"(fn [] \"|planet| => {{planet}}\")","__tag__":"code","perl":"sub { \"|planet| => {{planet}}\" }","python":"lambda: \"|planet| => {{planet}}\"","ruby":"proc { \"|planet| => {{planet}}\" }","js":"function() { return \"|planet| => {{planet}}\" }"}},"expected":"Hello, (|planet| => world)!","template":"{{= | | =}}\nHello, (|&lambda|)!","desc":"A lambda's return value should parse with the default delimiters."},{"name":"Interpolation - Multiple Calls","data":{"lambda":{"php":"global $calls; return ++$calls;","clojure":"(def g (atom 0)) (fn [] (swap! g inc))","__tag__":"code","perl":"sub { no strict; $calls += 1 }","python":"lambda: globals().update(calls=globals().get(\"calls\",0)+1) or calls","ruby":"proc { $calls ||= 0; $calls += 1 }","js":"function() { return (g=(function(){return this})()).calls=(g.calls||0)+1 }"}},"expected":"1 == 2 == 3","template":"{{lambda}} == {{{lambda}}} == {{lambda}}","desc":"Interpolated lambdas should not be cached."},{"name":"Escaping","data":{"lambda":{"php":"return \">\";","clojure":"(fn [] \">\")","__tag__":"code","perl":"sub { \">\" }","python":"lambda: \">\"","ruby":"proc { \">\" }","js":"function() { return \">\" }"}},"expected":"<>>","template":"<{{lambda}}{{{lambda}}}","desc":"Lambda results should be appropriately escaped."},{"name":"Section","data":{"x":"Error!","lambda":{"php":"return ($text == \"{{x}}\") ? \"yes\" : \"no\";","clojure":"(fn [text] (if (= text \"{{x}}\") \"yes\" \"no\"))","__tag__":"code","perl":"sub { $_[0] eq \"{{x}}\" ? \"yes\" : \"no\" }","python":"lambda text: text == \"{{x}}\" and \"yes\" or \"no\"","ruby":"proc { |text| text == \"{{x}}\" ? \"yes\" : \"no\" }","js":"function(txt) { return (txt == \"{{x}}\" ? \"yes\" : \"no\") }"}},"expected":"","template":"<{{#lambda}}{{x}}{{/lambda}}>","desc":"Lambdas used for sections should receive the raw section string."},{"name":"Section - Expansion","data":{"planet":"Earth","lambda":{"php":"return $text . \"{{planet}}\" . $text;","clojure":"(fn [text] (str text \"{{planet}}\" text))","__tag__":"code","perl":"sub { $_[0] . \"{{planet}}\" . $_[0] }","python":"lambda text: \"%s{{planet}}%s\" % (text, text)","ruby":"proc { |text| \"#{text}{{planet}}#{text}\" }","js":"function(txt) { return txt + \"{{planet}}\" + txt }"}},"expected":"<-Earth->","template":"<{{#lambda}}-{{/lambda}}>","desc":"Lambdas used for sections should have their results parsed."},{"name":"Section - Alternate Delimiters","data":{"planet":"Earth","lambda":{"php":"return $text . \"{{planet}} => |planet|\" . $text;","clojure":"(fn [text] (str text \"{{planet}} => |planet|\" text))","__tag__":"code","perl":"sub { $_[0] . \"{{planet}} => |planet|\" . $_[0] }","python":"lambda text: \"%s{{planet}} => |planet|%s\" % (text, text)","ruby":"proc { |text| \"#{text}{{planet}} => |planet|#{text}\" }","js":"function(txt) { return txt + \"{{planet}} => |planet|\" + txt }"}},"expected":"<-{{planet}} => Earth->","template":"{{= | | =}}<|#lambda|-|/lambda|>","desc":"Lambdas used for sections should parse with the current delimiters."},{"name":"Section - Multiple Calls","data":{"lambda":{"php":"return \"__\" . $text . \"__\";","clojure":"(fn [text] (str \"__\" text \"__\"))","__tag__":"code","perl":"sub { \"__\" . $_[0] . \"__\" }","python":"lambda text: \"__%s__\" % (text)","ruby":"proc { |text| \"__#{text}__\" }","js":"function(txt) { return \"__\" + txt + \"__\" }"}},"expected":"__FILE__ != __LINE__","template":"{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}","desc":"Lambdas used for sections should not be cached."},{"name":"Inverted Section","data":{"static":"static","lambda":{"php":"return false;","clojure":"(fn [text] false)","__tag__":"code","perl":"sub { 0 }","python":"lambda text: 0","ruby":"proc { |text| false }","js":"function(txt) { return false }"}},"expected":"<>","template":"<{{^lambda}}{{static}}{{/lambda}}>","desc":"Lambdas used for inverted sections should be considered truthy."}]} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/~lambdas.yml b/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/~lambdas.yml deleted file mode 100644 index b9fb4d0..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/spec/specs/~lambdas.yml +++ /dev/null @@ -1,149 +0,0 @@ -overview: | - Lambdas are a special-cased data type for use in interpolations and - sections. - - When used as the data value for an Interpolation tag, the lambda MUST be - treatable as an arity 0 function, and invoked as such. The returned value - MUST be rendered against the default delimiters, then interpolated in place - of the lambda. - - When used as the data value for a Section tag, the lambda MUST be treatable - as an arity 1 function, and invoked as such (passing a String containing the - unprocessed section contents). The returned value MUST be rendered against - the current delimiters, then interpolated in place of the section. -tests: - - name: Interpolation - desc: A lambda's return value should be interpolated. - data: - lambda: !code - ruby: 'proc { "world" }' - perl: 'sub { "world" }' - js: 'function() { return "world" }' - php: 'return "world";' - python: 'lambda: "world"' - clojure: '(fn [] "world")' - template: "Hello, {{lambda}}!" - expected: "Hello, world!" - - - name: Interpolation - Expansion - desc: A lambda's return value should be parsed. - data: - planet: "world" - lambda: !code - ruby: 'proc { "{{planet}}" }' - perl: 'sub { "{{planet}}" }' - js: 'function() { return "{{planet}}" }' - php: 'return "{{planet}}";' - python: 'lambda: "{{planet}}"' - clojure: '(fn [] "{{planet}}")' - template: "Hello, {{lambda}}!" - expected: "Hello, world!" - - - name: Interpolation - Alternate Delimiters - desc: A lambda's return value should parse with the default delimiters. - data: - planet: "world" - lambda: !code - ruby: 'proc { "|planet| => {{planet}}" }' - perl: 'sub { "|planet| => {{planet}}" }' - js: 'function() { return "|planet| => {{planet}}" }' - php: 'return "|planet| => {{planet}}";' - python: 'lambda: "|planet| => {{planet}}"' - clojure: '(fn [] "|planet| => {{planet}}")' - template: "{{= | | =}}\nHello, (|&lambda|)!" - expected: "Hello, (|planet| => world)!" - - - name: Interpolation - Multiple Calls - desc: Interpolated lambdas should not be cached. - data: - lambda: !code - ruby: 'proc { $calls ||= 0; $calls += 1 }' - perl: 'sub { no strict; $calls += 1 }' - js: 'function() { return (g=(function(){return this})()).calls=(g.calls||0)+1 }' - php: 'global $calls; return ++$calls;' - python: 'lambda: globals().update(calls=globals().get("calls",0)+1) or calls' - clojure: '(def g (atom 0)) (fn [] (swap! g inc))' - template: '{{lambda}} == {{{lambda}}} == {{lambda}}' - expected: '1 == 2 == 3' - - - name: Escaping - desc: Lambda results should be appropriately escaped. - data: - lambda: !code - ruby: 'proc { ">" }' - perl: 'sub { ">" }' - js: 'function() { return ">" }' - php: 'return ">";' - python: 'lambda: ">"' - clojure: '(fn [] ">")' - template: "<{{lambda}}{{{lambda}}}" - expected: "<>>" - - - name: Section - desc: Lambdas used for sections should receive the raw section string. - data: - x: 'Error!' - lambda: !code - ruby: 'proc { |text| text == "{{x}}" ? "yes" : "no" }' - perl: 'sub { $_[0] eq "{{x}}" ? "yes" : "no" }' - js: 'function(txt) { return (txt == "{{x}}" ? "yes" : "no") }' - php: 'return ($text == "{{x}}") ? "yes" : "no";' - python: 'lambda text: text == "{{x}}" and "yes" or "no"' - clojure: '(fn [text] (if (= text "{{x}}") "yes" "no"))' - template: "<{{#lambda}}{{x}}{{/lambda}}>" - expected: "" - - - name: Section - Expansion - desc: Lambdas used for sections should have their results parsed. - data: - planet: "Earth" - lambda: !code - ruby: 'proc { |text| "#{text}{{planet}}#{text}" }' - perl: 'sub { $_[0] . "{{planet}}" . $_[0] }' - js: 'function(txt) { return txt + "{{planet}}" + txt }' - php: 'return $text . "{{planet}}" . $text;' - python: 'lambda text: "%s{{planet}}%s" % (text, text)' - clojure: '(fn [text] (str text "{{planet}}" text))' - template: "<{{#lambda}}-{{/lambda}}>" - expected: "<-Earth->" - - - name: Section - Alternate Delimiters - desc: Lambdas used for sections should parse with the current delimiters. - data: - planet: "Earth" - lambda: !code - ruby: 'proc { |text| "#{text}{{planet}} => |planet|#{text}" }' - perl: 'sub { $_[0] . "{{planet}} => |planet|" . $_[0] }' - js: 'function(txt) { return txt + "{{planet}} => |planet|" + txt }' - php: 'return $text . "{{planet}} => |planet|" . $text;' - python: 'lambda text: "%s{{planet}} => |planet|%s" % (text, text)' - clojure: '(fn [text] (str text "{{planet}} => |planet|" text))' - template: "{{= | | =}}<|#lambda|-|/lambda|>" - expected: "<-{{planet}} => Earth->" - - - name: Section - Multiple Calls - desc: Lambdas used for sections should not be cached. - data: - lambda: !code - ruby: 'proc { |text| "__#{text}__" }' - perl: 'sub { "__" . $_[0] . "__" }' - js: 'function(txt) { return "__" + txt + "__" }' - php: 'return "__" . $text . "__";' - python: 'lambda text: "__%s__" % (text)' - clojure: '(fn [text] (str "__" text "__"))' - template: '{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}' - expected: '__FILE__ != __LINE__' - - - name: Inverted Section - desc: Lambdas used for inverted sections should be considered truthy. - data: - static: 'static' - lambda: !code - ruby: 'proc { |text| false }' - perl: 'sub { 0 }' - js: 'function(txt) { return false }' - php: 'return false;' - python: 'lambda text: 0' - clojure: '(fn [text] false)' - template: "<{{^lambda}}{{static}}{{/lambda}}>" - expected: "<>" diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/test/templates/list.mustache b/public/bootstrap/docs/build/node_modules/hogan.js/test/templates/list.mustache deleted file mode 100644 index 9bb653a..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/test/templates/list.mustache +++ /dev/null @@ -1,8 +0,0 @@ -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/tools/release.js b/public/bootstrap/docs/build/node_modules/hogan.js/tools/release.js deleted file mode 100644 index dda0d3f..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/tools/release.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var fs = require('fs'); -var path = require('path'); -var Hogan = require(__dirname + '/../lib/hogan'); -var minlicense = '/**\n* @preserve Copyright 2012 Twitter, Inc.\n* @license http://www.apache.org/licenses/LICENSE-2.0.txt\n*/\n'; - -function read(path) { - return fs.readFileSync(path).toString() -} - -// Good enough for little js files -function copy(src, dst) { - return fs.writeFileSync(dst, read(src)); -} - -function uglify(src, dst) { - var jsp = require("uglify-js").parser; - var pro = require("uglify-js").uglify; - var orig_code = read(src); - var ast = jsp.parse(orig_code); // parse code and get the initial AST - ast = pro.ast_mangle(ast); // get a new AST with mangled names - ast = pro.ast_squeeze(ast); // get an AST with compression optimizations - fs.writeFileSync(dst, minlicense + pro.gen_code(ast)); -} - -var packageJSON = JSON.parse(read('package.json')); -var version = packageJSON.version.substring(0, packageJSON.version.indexOf('-')); - -function removeFirstComment(text) { - return text.substring(text.indexOf('*/') + 2); -} - -var context = { - template: removeFirstComment(read(__dirname + '/../lib/template.js')), - compiler: removeFirstComment(read(__dirname + '/../lib/compiler.js')) -}; - -var wrapperPath = '/../wrappers/'; -var wrappers = fs.readdirSync(__dirname + wrapperPath).map(function(f) { - return __dirname + wrapperPath + f; -}); - -var distPath = __dirname + '/../dist/'; -wrappers.forEach(function(wrapper) { - var tail = path.basename(wrapper, '.mustache'); - var target = distPath + 'hogan-' + version + '.' + tail; - var uglified = distPath + 'hogan-' + version + '.min.' + tail; - fs.writeFileSync(target, Hogan.compile(read(wrapper)).render(context)); - uglify(target, uglified); -}); - -// Also release Hogan.Template on its own. -var templateTarget = distPath + 'template-' + version + '.js'; -fs.writeFileSync(templateTarget, read(__dirname + '/../lib/template.js')); -uglify(templateTarget, distPath + 'template-' + version + '.min.js'); - -// Add packageJSON to node distribution -packageJSON.version = version; -fs.writeFileSync(__dirname + '/../dist/nodejs/package.json', - JSON.stringify(packageJSON, null, " ")); diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/tools/web_templates.js b/public/bootstrap/docs/build/node_modules/hogan.js/tools/web_templates.js deleted file mode 100644 index f00acd3..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/tools/web_templates.js +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var Hogan = require(__dirname + '/../lib/hogan.js'); -var fs = require('fs'); -var path = require('path'); - -// Substitute variables in the homepage with values from package.json -var homeTemplatePath = __dirname + '/../build/gh-pages/index.html.mustache'; -var contextPath = __dirname + '/../dist/nodejs/package.json'; - -var homepage = fs.readFileSync(homeTemplatePath).toString(); -var context = JSON.parse(fs.readFileSync(contextPath).toString()); - -var template = Hogan.compile(homepage); - -fs.writeFileSync(path.dirname(homeTemplatePath) + '/index.html', - template.render(context)); - -fs.unlinkSync(homeTemplatePath); \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/1.0.0/hogan.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/1.0.0/hogan.js deleted file mode 100644 index 09170d6..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/1.0.0/hogan.js +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var HoganTemplate = (function () { - - function constructor(text) { - this.text = text; - }; - - constructor.prototype = { - // render: replaced by generated code. - r: function (context, partials) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials) { - return this.r(context, partials); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - return partial.render(context, partials); - }, - - // render a section - rs: function(context, partials, section) { - var buf = ''; - var tail = context[context.length - 1]; - if (!isArray(tail)) { - buf = section(context, partials); - return buf; - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end) { - if (isArray(val) && val.length === 0) { - return false; - } - - if (!inverted && typeof val == 'function') { - val = this.ls(val, ctx, partials, start, end); - } - - var pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - var names = key.split('.'); - var val = this.f(names[0], ctx, partials, returnFound); - var cx = null; - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false; - var v = null; - var found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text) { - var t = val.call(cx, text, function(t) { - return Hogan.compile(t).render(cx); - }); - var s = Hogan.compile(t.toString()).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, start, end) { - var cx = ctx[ctx.length - 1]; - if (val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end)); - } - var t = val.call(cx); - if (typeof t == 'function') { - return this.ho(t, cx, partials, this.text.substring(start, end)); - } - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - return Hogan.compile(val.call(cx).toString()).render(cx, partials); - } - }; - - var rAmp = /&/g, rLt = //g, rApos =/\'/g, - rQuot = /\"/g, hChars =/[&<>\"\']/; - function hoganEscape(str) { - var s = String(str === null ? '' : str); - return hChars.test(s) ? s.replace(rAmp,'&') - .replace(rLt,'<').replace(rGt,'>') - .replace(rApos,''').replace(rQuot, '"') : s; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - } - - return constructor; -})(); - -var Hogan = (function () { - - function scan(text) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) == null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart; j < tokens.length; j++) { - if (!tokens[j].tag) { - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}) - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag; - var closeIndex = text.indexOf(close, index); - var delimiters = trim(text.substring(text.indexOf('=', index) + 1, - closeIndex)).split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - return closeIndex + close.length - 1; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text[i] == '\n') { - filterLine(seenTag); - } else { - buf += text[i]; - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - var tag = tagTypes[text[i + 1]]; - tagType = tag ? text[i + 1] : '_v'; - seenTag = i; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - } else { - if (tagChange(ctag, text, i)) { - i += ctag.length - 1; - tokens.push({tag: tagType, n: trim(buf), - i: (tagType == '/') ? seenTag - 1 : i + 1}); - buf = ''; - state = IN_TEXT; - if (tagType == '{') { - i++; - } - } else { - buf += text[i]; - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/; - - var tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - function tagChange(tag, text, index) { - if (text[index] != tag[0]) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text[index + i] != tag[i]) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || - isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length == 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function generate(tree, text, options) { - var code = 'var c = [cx];var b = "";var _ = this;' + - walk(tree) + 'return b;'; - if (options.asString) { - return 'function(cx,p){' + code + ';};'; - } - - var template = new HoganTemplate(text); - template.r = new Function('cx', 'p', code); - return template; - } - - var rQuot = /\"/g, rNewline = /\n/g, rCr = /\r/g, rSlash = /\\/g; - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r') - }; - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i].n); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('\n'); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text(tree[i]); - } - } - return code; - } - - function section(nodes, id, method, start, end) { - var code = 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),'; - code += 'c,p,0,' + start + ',' + end + ')){'; - code += 'b += _.rs(c,p,'; - code += 'function(c,p){ var b = "";'; - code += walk(nodes); - code += 'return b;});c.pop();}'; - code += 'else{b += _.b; _.b = ""};'; - return code; - } - - function invertedSection(nodes, id, method) { - var code = 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0)){'; - code += walk(nodes); - code += '};'; - return code; - } - - function partial(id) { - return 'b += _.rp("' + esc(id) + '",c[c.length - 1],p);'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += "' + esc(id) + '";'; - } - - return ({ - scan: scan, - - parse: function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - cache: {}, - - compile: function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - options = options || {}; - - var t = this.cache[text]; - if (t) { - return t; - } - t = generate(this.parse(scan(text), options), text, options); - return this.cache[text] = t; - } - }); -})(); - -// Export the hogan constructor for Node.js and CommonJS. -if (typeof module !== 'undefined' && module.exports) { - module.exports = Hogan; - module.exports.Template = HoganTemplate; -} else if (typeof exports !== 'undefined') { - exports.Hogan = Hogan; - exports.HoganTemplate = HoganTemplate; -} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/1.0.0/hogan.min.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/1.0.0/hogan.min.js deleted file mode 100644 index 13ec535..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/1.0.0/hogan.min.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */var HoganTemplate=function(){function a(a){this.text=a}function h(a){var h=String(a===null?"":a);return g.test(h)?h.replace(b,"&").replace(c,"<").replace(d,">").replace(e,"'").replace(f,"""):h}a.prototype={r:function(a,b){return""},v:h,render:function(a,b){return this.r(a,b)},rp:function(a,b,c,d){var e=c[a];return e?e.render(b,c):""},rs:function(a,b,c){var d="",e=a[a.length-1];if(!i(e))return d=c(a,b),d;for(var f=0;f=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d){var e=a.call(b,d,function(a){return Hogan.compile(a).render(b)}),f=Hogan.compile(e.toString()).render(b,c);return this.b=f,!1},b:"",ls:function(a,b,c,d,e){var f=b[b.length-1];if(a.length>0)return this.ho(a,f,c,this.text.substring(d,e));var g=a.call(f);return typeof g=="function"?this.ho(g,f,c,this.text.substring(d,e)):g},lv:function(a,b,c){var d=b[b.length-1];return Hogan.compile(a.call(d).toString()).render(d,c)}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"};return a}(),Hogan=function(){function a(a){function s(){l.length>0&&(m.push(new String(l)),l="")}function t(){var a=!0;for(var b=p;b0){j=a.shift();if(j.tag=="#"||j.tag=="^"||g(j,d))c.push(j),j.nodes=f(a,j.tag,c,d),e.push(j);else{if(j.tag=="/"){if(c.length==0)throw new Error("Closing tag without opener: /"+j.n);i=c.pop();if(j.n!=i.n&&!h(j.n,i.n,d))throw new Error("Nesting error: "+i.n+" vs. "+j.n);return i.end=j.i,e}e.push(j)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function g(a,b){for(var c=0,d=b.length;c"?b+=s(a[c].n):e=="{"||e=="&"?b+=t(a[c].n,o(a[c].n)):e=="\n"?b+=v("\n"):e=="_v"?b+=u(a[c].n,o(a[c].n)):e===undefined&&(b+=v(a[c]))}return b}function q(a,b,c,d,e){var f="if(_.s(_."+c+'("'+n(b)+'",c,p,1),';return f+="c,p,0,"+d+","+e+")){",f+="b += _.rs(c,p,",f+='function(c,p){ var b = "";',f+=p(a),f+="return b;});c.pop();}",f+='else{b += _.b; _.b = ""};',f}function r(a,b,c){var d="if (!_.s(_."+c+'("'+n(b)+'",c,p,1),c,p,1,0,0)){';return d+=p(a),d+="};",d}function s(a){return'b += _.rp("'+n(a)+'",c[c.length - 1],p);'}function t(a,b){return"b += (_."+b+'("'+n(a)+'",c,p,0));'}function u(a,b){return"b += (_.v(_."+b+'("'+n(a)+'",c,p,0)));'}function v(a){return'b += "'+n(a)+'";'}var c=/\S/,d={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10},j=/\"/g,k=/\n/g,l=/\r/g,m=/\\/g;return{scan:a,parse:function(a,b){return b=b||{},f(a,"",[],b.sectionTags||[])},cache:{},compile:function(b,c){c=c||{};var d=this.cache[b];return d?d:(d=i(this.parse(a(b),c),b,c),this.cache[b]=d)}}}();typeof module!="undefined"&&module.exports?(module.exports=Hogan,module.exports.Template=HoganTemplate):typeof exports!="undefined"&&(exports.Hogan=Hogan,exports.HoganTemplate=HoganTemplate); \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.0/hogan.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.0/hogan.js deleted file mode 100644 index 09170d6..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.0/hogan.js +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var HoganTemplate = (function () { - - function constructor(text) { - this.text = text; - }; - - constructor.prototype = { - // render: replaced by generated code. - r: function (context, partials) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials) { - return this.r(context, partials); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - return partial.render(context, partials); - }, - - // render a section - rs: function(context, partials, section) { - var buf = ''; - var tail = context[context.length - 1]; - if (!isArray(tail)) { - buf = section(context, partials); - return buf; - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end) { - if (isArray(val) && val.length === 0) { - return false; - } - - if (!inverted && typeof val == 'function') { - val = this.ls(val, ctx, partials, start, end); - } - - var pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - var names = key.split('.'); - var val = this.f(names[0], ctx, partials, returnFound); - var cx = null; - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false; - var v = null; - var found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text) { - var t = val.call(cx, text, function(t) { - return Hogan.compile(t).render(cx); - }); - var s = Hogan.compile(t.toString()).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, start, end) { - var cx = ctx[ctx.length - 1]; - if (val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end)); - } - var t = val.call(cx); - if (typeof t == 'function') { - return this.ho(t, cx, partials, this.text.substring(start, end)); - } - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - return Hogan.compile(val.call(cx).toString()).render(cx, partials); - } - }; - - var rAmp = /&/g, rLt = //g, rApos =/\'/g, - rQuot = /\"/g, hChars =/[&<>\"\']/; - function hoganEscape(str) { - var s = String(str === null ? '' : str); - return hChars.test(s) ? s.replace(rAmp,'&') - .replace(rLt,'<').replace(rGt,'>') - .replace(rApos,''').replace(rQuot, '"') : s; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - } - - return constructor; -})(); - -var Hogan = (function () { - - function scan(text) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) == null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart; j < tokens.length; j++) { - if (!tokens[j].tag) { - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}) - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag; - var closeIndex = text.indexOf(close, index); - var delimiters = trim(text.substring(text.indexOf('=', index) + 1, - closeIndex)).split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - return closeIndex + close.length - 1; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text[i] == '\n') { - filterLine(seenTag); - } else { - buf += text[i]; - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - var tag = tagTypes[text[i + 1]]; - tagType = tag ? text[i + 1] : '_v'; - seenTag = i; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - } else { - if (tagChange(ctag, text, i)) { - i += ctag.length - 1; - tokens.push({tag: tagType, n: trim(buf), - i: (tagType == '/') ? seenTag - 1 : i + 1}); - buf = ''; - state = IN_TEXT; - if (tagType == '{') { - i++; - } - } else { - buf += text[i]; - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/; - - var tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - function tagChange(tag, text, index) { - if (text[index] != tag[0]) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text[index + i] != tag[i]) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || - isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length == 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function generate(tree, text, options) { - var code = 'var c = [cx];var b = "";var _ = this;' + - walk(tree) + 'return b;'; - if (options.asString) { - return 'function(cx,p){' + code + ';};'; - } - - var template = new HoganTemplate(text); - template.r = new Function('cx', 'p', code); - return template; - } - - var rQuot = /\"/g, rNewline = /\n/g, rCr = /\r/g, rSlash = /\\/g; - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r') - }; - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i].n); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('\n'); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text(tree[i]); - } - } - return code; - } - - function section(nodes, id, method, start, end) { - var code = 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),'; - code += 'c,p,0,' + start + ',' + end + ')){'; - code += 'b += _.rs(c,p,'; - code += 'function(c,p){ var b = "";'; - code += walk(nodes); - code += 'return b;});c.pop();}'; - code += 'else{b += _.b; _.b = ""};'; - return code; - } - - function invertedSection(nodes, id, method) { - var code = 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0)){'; - code += walk(nodes); - code += '};'; - return code; - } - - function partial(id) { - return 'b += _.rp("' + esc(id) + '",c[c.length - 1],p);'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += "' + esc(id) + '";'; - } - - return ({ - scan: scan, - - parse: function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - cache: {}, - - compile: function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - options = options || {}; - - var t = this.cache[text]; - if (t) { - return t; - } - t = generate(this.parse(scan(text), options), text, options); - return this.cache[text] = t; - } - }); -})(); - -// Export the hogan constructor for Node.js and CommonJS. -if (typeof module !== 'undefined' && module.exports) { - module.exports = Hogan; - module.exports.Template = HoganTemplate; -} else if (typeof exports !== 'undefined') { - exports.Hogan = Hogan; - exports.HoganTemplate = HoganTemplate; -} \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.0/hogan.min.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.0/hogan.min.js deleted file mode 100644 index 13ec535..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.0/hogan.min.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */var HoganTemplate=function(){function a(a){this.text=a}function h(a){var h=String(a===null?"":a);return g.test(h)?h.replace(b,"&").replace(c,"<").replace(d,">").replace(e,"'").replace(f,"""):h}a.prototype={r:function(a,b){return""},v:h,render:function(a,b){return this.r(a,b)},rp:function(a,b,c,d){var e=c[a];return e?e.render(b,c):""},rs:function(a,b,c){var d="",e=a[a.length-1];if(!i(e))return d=c(a,b),d;for(var f=0;f=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d){var e=a.call(b,d,function(a){return Hogan.compile(a).render(b)}),f=Hogan.compile(e.toString()).render(b,c);return this.b=f,!1},b:"",ls:function(a,b,c,d,e){var f=b[b.length-1];if(a.length>0)return this.ho(a,f,c,this.text.substring(d,e));var g=a.call(f);return typeof g=="function"?this.ho(g,f,c,this.text.substring(d,e)):g},lv:function(a,b,c){var d=b[b.length-1];return Hogan.compile(a.call(d).toString()).render(d,c)}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"};return a}(),Hogan=function(){function a(a){function s(){l.length>0&&(m.push(new String(l)),l="")}function t(){var a=!0;for(var b=p;b0){j=a.shift();if(j.tag=="#"||j.tag=="^"||g(j,d))c.push(j),j.nodes=f(a,j.tag,c,d),e.push(j);else{if(j.tag=="/"){if(c.length==0)throw new Error("Closing tag without opener: /"+j.n);i=c.pop();if(j.n!=i.n&&!h(j.n,i.n,d))throw new Error("Nesting error: "+i.n+" vs. "+j.n);return i.end=j.i,e}e.push(j)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function g(a,b){for(var c=0,d=b.length;c"?b+=s(a[c].n):e=="{"||e=="&"?b+=t(a[c].n,o(a[c].n)):e=="\n"?b+=v("\n"):e=="_v"?b+=u(a[c].n,o(a[c].n)):e===undefined&&(b+=v(a[c]))}return b}function q(a,b,c,d,e){var f="if(_.s(_."+c+'("'+n(b)+'",c,p,1),';return f+="c,p,0,"+d+","+e+")){",f+="b += _.rs(c,p,",f+='function(c,p){ var b = "";',f+=p(a),f+="return b;});c.pop();}",f+='else{b += _.b; _.b = ""};',f}function r(a,b,c){var d="if (!_.s(_."+c+'("'+n(b)+'",c,p,1),c,p,1,0,0)){';return d+=p(a),d+="};",d}function s(a){return'b += _.rp("'+n(a)+'",c[c.length - 1],p);'}function t(a,b){return"b += (_."+b+'("'+n(a)+'",c,p,0));'}function u(a,b){return"b += (_.v(_."+b+'("'+n(a)+'",c,p,0)));'}function v(a){return'b += "'+n(a)+'";'}var c=/\S/,d={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10},j=/\"/g,k=/\n/g,l=/\r/g,m=/\\/g;return{scan:a,parse:function(a,b){return b=b||{},f(a,"",[],b.sectionTags||[])},cache:{},compile:function(b,c){c=c||{};var d=this.cache[b];return d?d:(d=i(this.parse(a(b),c),b,c),this.cache[b]=d)}}}();typeof module!="undefined"&&module.exports?(module.exports=Hogan,module.exports.Template=HoganTemplate):typeof exports!="undefined"&&(exports.Hogan=Hogan,exports.HoganTemplate=HoganTemplate); \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.3/hogan.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.3/hogan.js deleted file mode 100644 index 4f6f6d2..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.3/hogan.js +++ /dev/null @@ -1,545 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var HoganTemplate = (function () { - - function constructor(text) { - this.text = text; - } - - constructor.prototype = { - - // render: replaced by generated code. - r: function (context, partials, indent) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials, indent) { - return this.r(context, partials, indent); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - return partial.r(context, partials, indent); - }, - - // render a section - rs: function(context, partials, section) { - var buf = '', - tail = context[context.length - 1]; - - if (!isArray(tail)) { - return buf = section(context, partials); - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end, tags) { - var pass; - - if (isArray(val) && val.length === 0) { - return false; - } - - if (!inverted && typeof val == 'function') { - val = this.ls(val, ctx, partials, start, end, tags); - } - - pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - - var names = key.split('.'), - val = this.f(names[0], ctx, partials, returnFound), - cx = null; - - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false, - v = null, - found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var t = val.call(cx, text, function(t) { - return Hogan.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = Hogan.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = val.call(cx); - - if (val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - if (typeof t == 'function') { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - return Hogan.compile(val.call(cx).toString()).render(cx, partials); - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String(str === null ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - - return constructor; - -})(); - -var Hogan = (function () { - - // Setup regex assignments - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/, - rQuot = /\"/g, - rNewline = /\n/g, - rCr = /\r/g, - rSlash = /\\/g, - tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - function scan(text, delimiters) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - tag = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart, next; j < tokens.length; j++) { - if (!tokens[j].tag) { - if ((next = tokens[j+1]) && next.tag == '>') { - // set indent to token value - next.indent = tokens[j].toString() - } - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}); - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag, - closeIndex = text.indexOf(close, index), - delimiters = trim( - text.substring(text.indexOf('=', index) + 1, closeIndex) - ).split(' '); - - otag = delimiters[0]; - ctag = delimiters[1]; - - return closeIndex + close.length - 1; - } - - if (delimiters) { - delimiters = delimiters.split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text.charAt(i) == '\n') { - filterLine(seenTag); - } else { - buf += text.charAt(i); - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - tag = tagTypes[text.charAt(i + 1)]; - tagType = tag ? text.charAt(i + 1) : '_v'; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - seenTag = i; - } else { - if (tagChange(ctag, text, i)) { - tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, - i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); - buf = ''; - i += ctag.length - 1; - state = IN_TEXT; - if (tagType == '{') { - i++; - } - } else { - buf += text.charAt(i); - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - function tagChange(tag, text, index) { - if (text.charAt(index) != tag.charAt(0)) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text.charAt(index + i) != tag.charAt(i)) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length === 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function generate(tree, text, options) { - var code = 'i = i || "";var c = [cx];var b = i + "";var _ = this;' - + walk(tree) - + 'return b;'; - - if (options.asString) { - return 'function(cx,p,i){' + code + ';}'; - } - - var template = new HoganTemplate(text); - template.r = new Function('cx', 'p', 'i', code); - return template; - } - - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r'); - } - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i]); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text('"' + esc(tree[i]) + '"'); - } - } - return code; - } - - function section(nodes, id, method, start, end, tags) { - return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + - 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' + - 'b += _.rs(c,p,' + - 'function(c,p){ var b = "";' + - walk(nodes) + - 'return b;});c.pop();}' + - 'else{b += _.b; _.b = ""};'; - } - - function invertedSection(nodes, id, method) { - return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + - walk(nodes) + - '};'; - } - - function partial(tok) { - return 'b += _.rp("' + esc(tok.n) + '",c[c.length - 1],p,"' + (tok.indent || '') + '");'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += ' + id + ';'; - } - - return ({ - scan: scan, - - parse: function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - cache: {}, - - compile: function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - // delimiters: A string that overrides the default delimiters. - // Example: "<% %>" - // - options = options || {}; - - var t = this.cache[text]; - - if (t) { - return t; - } - - t = generate(this.parse(scan(text, options.delimiters), options), text, options); - return this.cache[text] = t; - } - }); -})(); - -// Export the hogan constructor for Node.js and CommonJS. -if (typeof module !== 'undefined' && module.exports) { - module.exports = Hogan; - module.exports.Template = HoganTemplate; -} else if (typeof define === 'function' && define.amd) { - define(function () { return Hogan; }); -} else if (typeof exports !== 'undefined') { - exports.Hogan = Hogan; - exports.HoganTemplate = HoganTemplate; -} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.3/hogan.min.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.3/hogan.min.js deleted file mode 100644 index 0af8a36..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.3/hogan.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/** -* @preserve Copyright 2012 Twitter, Inc. -* @license http://www.apache.org/licenses/LICENSE-2.0.txt -*/ -var HoganTemplate=function(){function a(a){this.text=a}function h(a){return a=String(a===null?"":a),g.test(a)?a.replace(b,"&").replace(c,"<").replace(d,">").replace(e,"'").replace(f,"""):a}a.prototype={r:function(a,b,c){return""},v:h,render:function(b,c,d){return this.r(b,c,d)},rp:function(a,b,c,d){var e=c[a];return e?e.r(b,c,d):""},rs:function(a,b,c){var d="",e=a[a.length-1];if(!i(e))return d=c(a,b);for(var f=0;f=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=a.call(b,d,function(a){return Hogan.compile(a,{delimiters:e}).render(b,c)}),g=Hogan.compile(f.toString(),{delimiters:e}).render(b,c);return this.b=g,!1},b:"",ls:function(a,b,c,d,e,f){var g=b[b.length-1],h=a.call(g);return a.length>0?this.ho(a,g,c,this.text.substring(d,e),f):typeof h=="function"?this.ho(h,g,c,this.text.substring(d,e),f):h},lv:function(a,b,c){var d=b[b.length-1];return Hogan.compile(a.call(d).toString()).render(d,c)}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"};return a}(),Hogan=function(){function g(b,c){function u(){n.length>0&&(o.push(new String(n)),n="")}function v(){var b=!0;for(var c=r;c"&&(d.indent=o[c].toString()),o.splice(c,1));else b||o.push({tag:"\n"});p=!1,r=o.length}function x(a,b){var c="="+t,d=a.indexOf(c,b),e=h(a.substring(a.indexOf("=",b)+1,d)).split(" ");return s=e[0],t=e[1],d+c.length-1}var d=b.length,e=0,g=1,j=2,k=e,l=null,m=null,n="",o=[],p=!1,q=0,r=0,s="{{",t="}}";c&&(c=c.split(" "),s=c[0],t=c[1]);for(q=0;q0){g=a.shift();if(g.tag=="#"||g.tag=="^"||k(g,d))c.push(g),g.nodes=j(a,g.tag,c,d),e.push(g);else{if(g.tag=="/"){if(c.length===0)throw new Error("Closing tag without opener: /"+g.n);f=c.pop();if(g.n!=f.n&&!l(g.n,f.n,d))throw new Error("Nesting error: "+f.n+" vs. "+g.n);return f.end=g.i,e}e.push(g)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function k(a,b){for(var c=0,d=b.length;c"?b+=s(a[c]):e=="{"||e=="&"?b+=t(a[c].n,o(a[c].n)):e=="\n"?b+=v('"\\n"'+(a.length-1==c?"":" + i")):e=="_v"?b+=u(a[c].n,o(a[c].n)):e===undefined&&(b+=v('"'+n(a[c])+'"'))}return b}function q(a,b,c,d,e,f){return"if(_.s(_."+c+'("'+n(b)+'",c,p,1),'+"c,p,0,"+d+","+e+', "'+f+'")){'+"b += _.rs(c,p,"+'function(c,p){ var b = "";'+p(a)+"return b;});c.pop();}"+'else{b += _.b; _.b = ""};'}function r(a,b,c){return"if (!_.s(_."+c+'("'+n(b)+'",c,p,1),c,p,1,0,0,"")){'+p(a)+"};"}function s(a){return'b += _.rp("'+n(a.n)+'",c[c.length - 1],p,"'+(a.indent||"")+'");'}function t(a,b){return"b += (_."+b+'("'+n(a)+'",c,p,0));'}function u(a,b){return"b += (_.v(_."+b+'("'+n(a)+'",c,p,0)));'}function v(a){return"b += "+a+";"}var a=/\S/,b=/\"/g,c=/\n/g,d=/\r/g,e=/\\/g,f={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10};return{scan:g,parse:function(a,b){return b=b||{},j(a,"",[],b.sectionTags||[])},cache:{},compile:function(a,b){b=b||{};var c=this.cache[a];return c?c:(c=m(this.parse(g(a,b.delimiters),b),a,b),this.cache[a]=c)}}}();typeof module!="undefined"&&module.exports?(module.exports=Hogan,module.exports.Template=HoganTemplate):typeof define=="function"&&define.amd?define(function(){return Hogan}):typeof exports!="undefined"&&(exports.Hogan=Hogan,exports.HoganTemplate=HoganTemplate) \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.amd.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.amd.js deleted file mode 100644 index ec55a5d..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.amd.js +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -var Hogan = {}; - -(function (Hogan) { - Hogan.Template = function constructor(renderFunc, text, compiler) { - if (renderFunc) { - this.r = renderFunc; - } - this.c = compiler; - this.text = text || ''; - } - - Hogan.Template.prototype = { - // render: replaced by generated code. - r: function (context, partials, indent) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials, indent) { - return this.ri([context], partials || {}, indent); - }, - - // render internal -- a hook for overrides that catches partials too - ri: function (context, partials, indent) { - return this.r(context, partials, indent); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - if (this.c && typeof partial == 'string') { - partial = this.c.compile(partial); - } - - return partial.ri(context, partials, indent); - }, - - // render a section - rs: function(context, partials, section) { - var buf = '', - tail = context[context.length - 1]; - - if (!isArray(tail)) { - return buf = section(context, partials); - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end, tags) { - var pass; - - if (isArray(val) && val.length === 0) { - return false; - } - - if (typeof val == 'function') { - val = this.ls(val, ctx, partials, inverted, start, end, tags); - } - - pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - var names = key.split('.'), - val = this.f(names[0], ctx, partials, returnFound), - cx = null; - - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false, - v = null, - found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var compiler = this.c; - var t = val.call(cx, text, function(t) { - return compiler.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, inverted, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = null; - - if (!inverted && this.c && val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - t = val.call(cx); - - if (typeof t == 'function') { - if (inverted) { - return true; - } else if (this.c) { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - var result = val.call(cx); - if (typeof result == 'function') { - result = result.call(cx); - } - result = result.toString(); - - if (this.c && ~result.indexOf("{{")) { - return this.c.compile(result).render(cx, partials); - } - - return result; - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String((str === null || str === undefined) ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - -})(typeof exports !== 'undefined' ? exports : Hogan); - - - - -(function (Hogan) { - // Setup regex assignments - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/, - rQuot = /\"/g, - rNewline = /\n/g, - rCr = /\r/g, - rSlash = /\\/g, - tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - Hogan.scan = function scan(text, delimiters) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - tag = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart, next; j < tokens.length; j++) { - if (!tokens[j].tag) { - if ((next = tokens[j+1]) && next.tag == '>') { - // set indent to token value - next.indent = tokens[j].toString() - } - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}); - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag, - closeIndex = text.indexOf(close, index), - delimiters = trim( - text.substring(text.indexOf('=', index) + 1, closeIndex) - ).split(' '); - - otag = delimiters[0]; - ctag = delimiters[1]; - - return closeIndex + close.length - 1; - } - - if (delimiters) { - delimiters = delimiters.split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text.charAt(i) == '\n') { - filterLine(seenTag); - } else { - buf += text.charAt(i); - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - tag = tagTypes[text.charAt(i + 1)]; - tagType = tag ? text.charAt(i + 1) : '_v'; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - seenTag = i; - } else { - if (tagChange(ctag, text, i)) { - tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, - i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); - buf = ''; - i += ctag.length - 1; - state = IN_TEXT; - if (tagType == '{') { - if (ctag == '}}') { - i++; - } else { - cleanTripleStache(tokens[tokens.length - 1]); - } - } - } else { - buf += text.charAt(i); - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function cleanTripleStache(token) { - if (token.n.substr(token.n.length - 1) === '}') { - token.n = token.n.substring(0, token.n.length - 1); - } - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - function tagChange(tag, text, index) { - if (text.charAt(index) != tag.charAt(0)) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text.charAt(index + i) != tag.charAt(i)) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length === 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function writeCode(tree) { - return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;'; - } - - Hogan.generate = function (code, text, options) { - if (options.asString) { - return 'function(c,p,i){' + code + ';}'; - } - - return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan); - } - - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r'); - } - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i]); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text('"' + esc(tree[i]) + '"'); - } - } - return code; - } - - function section(nodes, id, method, start, end, tags) { - return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + - 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' + - 'b += _.rs(c,p,' + - 'function(c,p){ var b = "";' + - walk(nodes) + - 'return b;});c.pop();}' + - 'else{b += _.b; _.b = ""};'; - } - - function invertedSection(nodes, id, method) { - return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + - walk(nodes) + - '};'; - } - - function partial(tok) { - return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += ' + id + ';'; - } - - Hogan.parse = function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - Hogan.cache = {}; - - Hogan.compile = function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - // delimiters: A string that overrides the default delimiters. - // Example: "<% %>" - // - options = options || {}; - - var key = text + '||' + !!options.asString; - - var t = this.cache[key]; - - if (t) { - return t; - } - - t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options); - return this.cache[key] = t; - }; -})(typeof exports !== 'undefined' ? exports : Hogan); - - -if (typeof define === 'function' && define.amd) { - define(Hogan); -} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.common.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.common.js deleted file mode 100644 index 7520652..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.common.js +++ /dev/null @@ -1,576 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -var Hogan = {}; - -(function (Hogan) { - Hogan.Template = function constructor(renderFunc, text, compiler) { - if (renderFunc) { - this.r = renderFunc; - } - this.c = compiler; - this.text = text || ''; - } - - Hogan.Template.prototype = { - // render: replaced by generated code. - r: function (context, partials, indent) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials, indent) { - return this.ri([context], partials || {}, indent); - }, - - // render internal -- a hook for overrides that catches partials too - ri: function (context, partials, indent) { - return this.r(context, partials, indent); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - if (this.c && typeof partial == 'string') { - partial = this.c.compile(partial); - } - - return partial.ri(context, partials, indent); - }, - - // render a section - rs: function(context, partials, section) { - var buf = '', - tail = context[context.length - 1]; - - if (!isArray(tail)) { - return buf = section(context, partials); - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end, tags) { - var pass; - - if (isArray(val) && val.length === 0) { - return false; - } - - if (typeof val == 'function') { - val = this.ls(val, ctx, partials, inverted, start, end, tags); - } - - pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - var names = key.split('.'), - val = this.f(names[0], ctx, partials, returnFound), - cx = null; - - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false, - v = null, - found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var compiler = this.c; - var t = val.call(cx, text, function(t) { - return compiler.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, inverted, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = null; - - if (!inverted && this.c && val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - t = val.call(cx); - - if (typeof t == 'function') { - if (inverted) { - return true; - } else if (this.c) { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - var result = val.call(cx); - if (typeof result == 'function') { - result = result.call(cx); - } - result = result.toString(); - - if (this.c && ~result.indexOf("{{")) { - return this.c.compile(result).render(cx, partials); - } - - return result; - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String((str === null || str === undefined) ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - -})(typeof exports !== 'undefined' ? exports : Hogan); - - - - -(function (Hogan) { - // Setup regex assignments - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/, - rQuot = /\"/g, - rNewline = /\n/g, - rCr = /\r/g, - rSlash = /\\/g, - tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - Hogan.scan = function scan(text, delimiters) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - tag = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart, next; j < tokens.length; j++) { - if (!tokens[j].tag) { - if ((next = tokens[j+1]) && next.tag == '>') { - // set indent to token value - next.indent = tokens[j].toString() - } - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}); - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag, - closeIndex = text.indexOf(close, index), - delimiters = trim( - text.substring(text.indexOf('=', index) + 1, closeIndex) - ).split(' '); - - otag = delimiters[0]; - ctag = delimiters[1]; - - return closeIndex + close.length - 1; - } - - if (delimiters) { - delimiters = delimiters.split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text.charAt(i) == '\n') { - filterLine(seenTag); - } else { - buf += text.charAt(i); - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - tag = tagTypes[text.charAt(i + 1)]; - tagType = tag ? text.charAt(i + 1) : '_v'; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - seenTag = i; - } else { - if (tagChange(ctag, text, i)) { - tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, - i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); - buf = ''; - i += ctag.length - 1; - state = IN_TEXT; - if (tagType == '{') { - if (ctag == '}}') { - i++; - } else { - cleanTripleStache(tokens[tokens.length - 1]); - } - } - } else { - buf += text.charAt(i); - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function cleanTripleStache(token) { - if (token.n.substr(token.n.length - 1) === '}') { - token.n = token.n.substring(0, token.n.length - 1); - } - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - function tagChange(tag, text, index) { - if (text.charAt(index) != tag.charAt(0)) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text.charAt(index + i) != tag.charAt(i)) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length === 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function writeCode(tree) { - return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;'; - } - - Hogan.generate = function (code, text, options) { - if (options.asString) { - return 'function(c,p,i){' + code + ';}'; - } - - return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan); - } - - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r'); - } - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i]); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text('"' + esc(tree[i]) + '"'); - } - } - return code; - } - - function section(nodes, id, method, start, end, tags) { - return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + - 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' + - 'b += _.rs(c,p,' + - 'function(c,p){ var b = "";' + - walk(nodes) + - 'return b;});c.pop();}' + - 'else{b += _.b; _.b = ""};'; - } - - function invertedSection(nodes, id, method) { - return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + - walk(nodes) + - '};'; - } - - function partial(tok) { - return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += ' + id + ';'; - } - - Hogan.parse = function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - Hogan.cache = {}; - - Hogan.compile = function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - // delimiters: A string that overrides the default delimiters. - // Example: "<% %>" - // - options = options || {}; - - var key = text + '||' + !!options.asString; - - var t = this.cache[key]; - - if (t) { - return t; - } - - t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options); - return this.cache[key] = t; - }; -})(typeof exports !== 'undefined' ? exports : Hogan); - - -if (typeof module !== 'undefined' && module.exports) { - module.exports = Hogan; -} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.js deleted file mode 100644 index 1807562..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.js +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - - -var Hogan = {}; - -(function (Hogan) { - Hogan.Template = function constructor(renderFunc, text, compiler) { - if (renderFunc) { - this.r = renderFunc; - } - this.c = compiler; - this.text = text || ''; - } - - Hogan.Template.prototype = { - // render: replaced by generated code. - r: function (context, partials, indent) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials, indent) { - return this.ri([context], partials || {}, indent); - }, - - // render internal -- a hook for overrides that catches partials too - ri: function (context, partials, indent) { - return this.r(context, partials, indent); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - if (this.c && typeof partial == 'string') { - partial = this.c.compile(partial); - } - - return partial.ri(context, partials, indent); - }, - - // render a section - rs: function(context, partials, section) { - var buf = '', - tail = context[context.length - 1]; - - if (!isArray(tail)) { - return buf = section(context, partials); - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end, tags) { - var pass; - - if (isArray(val) && val.length === 0) { - return false; - } - - if (typeof val == 'function') { - val = this.ls(val, ctx, partials, inverted, start, end, tags); - } - - pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - var names = key.split('.'), - val = this.f(names[0], ctx, partials, returnFound), - cx = null; - - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false, - v = null, - found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var compiler = this.c; - var t = val.call(cx, text, function(t) { - return compiler.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, inverted, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = null; - - if (!inverted && this.c && val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - t = val.call(cx); - - if (typeof t == 'function') { - if (inverted) { - return true; - } else if (this.c) { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - var result = val.call(cx); - if (typeof result == 'function') { - result = result.call(cx); - } - result = result.toString(); - - if (this.c && ~result.indexOf("{{")) { - return this.c.compile(result).render(cx, partials); - } - - return result; - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String((str === null || str === undefined) ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - -})(typeof exports !== 'undefined' ? exports : Hogan); - - - - -(function (Hogan) { - // Setup regex assignments - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/, - rQuot = /\"/g, - rNewline = /\n/g, - rCr = /\r/g, - rSlash = /\\/g, - tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - Hogan.scan = function scan(text, delimiters) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - tag = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart, next; j < tokens.length; j++) { - if (!tokens[j].tag) { - if ((next = tokens[j+1]) && next.tag == '>') { - // set indent to token value - next.indent = tokens[j].toString() - } - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}); - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag, - closeIndex = text.indexOf(close, index), - delimiters = trim( - text.substring(text.indexOf('=', index) + 1, closeIndex) - ).split(' '); - - otag = delimiters[0]; - ctag = delimiters[1]; - - return closeIndex + close.length - 1; - } - - if (delimiters) { - delimiters = delimiters.split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text.charAt(i) == '\n') { - filterLine(seenTag); - } else { - buf += text.charAt(i); - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - tag = tagTypes[text.charAt(i + 1)]; - tagType = tag ? text.charAt(i + 1) : '_v'; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - seenTag = i; - } else { - if (tagChange(ctag, text, i)) { - tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, - i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); - buf = ''; - i += ctag.length - 1; - state = IN_TEXT; - if (tagType == '{') { - if (ctag == '}}') { - i++; - } else { - cleanTripleStache(tokens[tokens.length - 1]); - } - } - } else { - buf += text.charAt(i); - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function cleanTripleStache(token) { - if (token.n.substr(token.n.length - 1) === '}') { - token.n = token.n.substring(0, token.n.length - 1); - } - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - function tagChange(tag, text, index) { - if (text.charAt(index) != tag.charAt(0)) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text.charAt(index + i) != tag.charAt(i)) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length === 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function writeCode(tree) { - return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;'; - } - - Hogan.generate = function (code, text, options) { - if (options.asString) { - return 'function(c,p,i){' + code + ';}'; - } - - return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan); - } - - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r'); - } - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i]); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text('"' + esc(tree[i]) + '"'); - } - } - return code; - } - - function section(nodes, id, method, start, end, tags) { - return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + - 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' + - 'b += _.rs(c,p,' + - 'function(c,p){ var b = "";' + - walk(nodes) + - 'return b;});c.pop();}' + - 'else{b += _.b; _.b = ""};'; - } - - function invertedSection(nodes, id, method) { - return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + - walk(nodes) + - '};'; - } - - function partial(tok) { - return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += ' + id + ';'; - } - - Hogan.parse = function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - Hogan.cache = {}; - - Hogan.compile = function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - // delimiters: A string that overrides the default delimiters. - // Example: "<% %>" - // - options = options || {}; - - var key = text + '||' + !!options.asString; - - var t = this.cache[key]; - - if (t) { - return t; - } - - t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options); - return this.cache[key] = t; - }; -})(typeof exports !== 'undefined' ? exports : Hogan); - diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.min.amd.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.min.amd.js deleted file mode 100644 index aee5922..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/hogan-1.0.5.min.amd.js +++ /dev/null @@ -1,5 +0,0 @@ -/** -* @preserve Copyright 2012 Twitter, Inc. -* @license http://www.apache.org/licenses/LICENSE-2.0.txt -*/ -var Hogan={};(function(a){function h(a){return a=String(a===null||a===undefined?"":a),g.test(a)?a.replace(b,"&").replace(c,"<").replace(d,">").replace(e,"'").replace(f,"""):a}a.Template=function j(a,b,c){a&&(this.r=a),this.c=c,this.text=b||""},a.Template.prototype={r:function(a,b,c){return""},v:h,render:function(b,c,d){return this.ri([b],c||{},d)},ri:function(a,b,c){return this.r(a,b,c)},rp:function(a,b,c,d){var e=c[a];return e?(this.c&&typeof e=="string"&&(e=this.c.compile(e)),e.ri(b,c,d)):""},rs:function(a,b,c){var d="",e=a[a.length-1];if(!i(e))return d=c(a,b);for(var f=0;f=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=this.c,g=a.call(b,d,function(a){return f.compile(a,{delimiters:e}).render(b,c)}),h=f.compile(g.toString(),{delimiters:e}).render(b,c);return this.b=h,!1},b:"",ls:function(a,b,c,d,e,f,g){var h=b[b.length-1],i=null;if(!d&&this.c&&a.length>0)return this.ho(a,h,c,this.text.substring(e,f),g);i=a.call(h);if(typeof i=="function"){if(d)return!0;if(this.c)return this.ho(i,h,c,this.text.substring(e,f),g)}return i},lv:function(a,b,c){var d=b[b.length-1],e=a.call(d);return typeof e=="function"&&(e=e.call(d)),e=e.toString(),this.c&&~e.indexOf("{{")?this.c.compile(e).render(d,c):e}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"}})(typeof exports!="undefined"?exports:Hogan),function(a){function h(a){a.n.substr(a.n.length-1)==="}"&&(a.n=a.n.substring(0,a.n.length-1))}function i(a){return a.trim?a.trim():a.replace(/^\s*|\s*$/g,"")}function j(a,b,c){if(b.charAt(c)!=a.charAt(0))return!1;for(var d=1,e=a.length;d0){g=a.shift();if(g.tag=="#"||g.tag=="^"||l(g,d))c.push(g),g.nodes=k(a,g.tag,c,d),e.push(g);else{if(g.tag=="/"){if(c.length===0)throw new Error("Closing tag without opener: /"+g.n);f=c.pop();if(g.n!=f.n&&!m(g.n,f.n,d))throw new Error("Nesting error: "+f.n+" vs. "+g.n);return f.end=g.i,e}e.push(g)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function l(a,b){for(var c=0,d=b.length;c"?b+=t(a[c]):e=="{"||e=="&"?b+=u(a[c].n,p(a[c].n)):e=="\n"?b+=w('"\\n"'+(a.length-1==c?"":" + i")):e=="_v"?b+=v(a[c].n,p(a[c].n)):e===undefined&&(b+=w('"'+o(a[c])+'"'))}return b}function r(a,b,c,d,e,f){return"if(_.s(_."+c+'("'+o(b)+'",c,p,1),'+"c,p,0,"+d+","+e+', "'+f+'")){'+"b += _.rs(c,p,"+'function(c,p){ var b = "";'+q(a)+"return b;});c.pop();}"+'else{b += _.b; _.b = ""};'}function s(a,b,c){return"if (!_.s(_."+c+'("'+o(b)+'",c,p,1),c,p,1,0,0,"")){'+q(a)+"};"}function t(a){return'b += _.rp("'+o(a.n)+'",c,p,"'+(a.indent||"")+'");'}function u(a,b){return"b += (_."+b+'("'+o(a)+'",c,p,0));'}function v(a,b){return"b += (_.v(_."+b+'("'+o(a)+'",c,p,0)));'}function w(a){return"b += "+a+";"}var b=/\S/,c=/\"/g,d=/\n/g,e=/\r/g,f=/\\/g,g={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10};a.scan=function(c,d){function w(){p.length>0&&(q.push(new String(p)),p="")}function x(){var a=!0;for(var c=t;c"&&(d.indent=q[c].toString()),q.splice(c,1));else b||q.push({tag:"\n"});r=!1,t=q.length}function z(a,b){var c="="+v,d=a.indexOf(c,b),e=i(a.substring(a.indexOf("=",b)+1,d)).split(" ");return u=e[0],v=e[1],d+c.length-1}var e=c.length,f=0,k=1,l=2,m=f,n=null,o=null,p="",q=[],r=!1,s=0,t=0,u="{{",v="}}";d&&(d=d.split(" "),u=d[0],v=d[1]);for(s=0;s=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=this.c,g=a.call(b,d,function(a){return f.compile(a,{delimiters:e}).render(b,c)}),h=f.compile(g.toString(),{delimiters:e}).render(b,c);return this.b=h,!1},b:"",ls:function(a,b,c,d,e,f,g){var h=b[b.length-1],i=null;if(!d&&this.c&&a.length>0)return this.ho(a,h,c,this.text.substring(e,f),g);i=a.call(h);if(typeof i=="function"){if(d)return!0;if(this.c)return this.ho(i,h,c,this.text.substring(e,f),g)}return i},lv:function(a,b,c){var d=b[b.length-1],e=a.call(d);return typeof e=="function"&&(e=e.call(d)),e=e.toString(),this.c&&~e.indexOf("{{")?this.c.compile(e).render(d,c):e}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"}})(typeof exports!="undefined"?exports:Hogan),function(a){function h(a){a.n.substr(a.n.length-1)==="}"&&(a.n=a.n.substring(0,a.n.length-1))}function i(a){return a.trim?a.trim():a.replace(/^\s*|\s*$/g,"")}function j(a,b,c){if(b.charAt(c)!=a.charAt(0))return!1;for(var d=1,e=a.length;d0){g=a.shift();if(g.tag=="#"||g.tag=="^"||l(g,d))c.push(g),g.nodes=k(a,g.tag,c,d),e.push(g);else{if(g.tag=="/"){if(c.length===0)throw new Error("Closing tag without opener: /"+g.n);f=c.pop();if(g.n!=f.n&&!m(g.n,f.n,d))throw new Error("Nesting error: "+f.n+" vs. "+g.n);return f.end=g.i,e}e.push(g)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function l(a,b){for(var c=0,d=b.length;c"?b+=t(a[c]):e=="{"||e=="&"?b+=u(a[c].n,p(a[c].n)):e=="\n"?b+=w('"\\n"'+(a.length-1==c?"":" + i")):e=="_v"?b+=v(a[c].n,p(a[c].n)):e===undefined&&(b+=w('"'+o(a[c])+'"'))}return b}function r(a,b,c,d,e,f){return"if(_.s(_."+c+'("'+o(b)+'",c,p,1),'+"c,p,0,"+d+","+e+', "'+f+'")){'+"b += _.rs(c,p,"+'function(c,p){ var b = "";'+q(a)+"return b;});c.pop();}"+'else{b += _.b; _.b = ""};'}function s(a,b,c){return"if (!_.s(_."+c+'("'+o(b)+'",c,p,1),c,p,1,0,0,"")){'+q(a)+"};"}function t(a){return'b += _.rp("'+o(a.n)+'",c,p,"'+(a.indent||"")+'");'}function u(a,b){return"b += (_."+b+'("'+o(a)+'",c,p,0));'}function v(a,b){return"b += (_.v(_."+b+'("'+o(a)+'",c,p,0)));'}function w(a){return"b += "+a+";"}var b=/\S/,c=/\"/g,d=/\n/g,e=/\r/g,f=/\\/g,g={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10};a.scan=function(c,d){function w(){p.length>0&&(q.push(new String(p)),p="")}function x(){var a=!0;for(var c=t;c"&&(d.indent=q[c].toString()),q.splice(c,1));else b||q.push({tag:"\n"});r=!1,t=q.length}function z(a,b){var c="="+v,d=a.indexOf(c,b),e=i(a.substring(a.indexOf("=",b)+1,d)).split(" ");return u=e[0],v=e[1],d+c.length-1}var e=c.length,f=0,k=1,l=2,m=f,n=null,o=null,p="",q=[],r=!1,s=0,t=0,u="{{",v="}}";d&&(d=d.split(" "),u=d[0],v=d[1]);for(s=0;s=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=this.c,g=a.call(b,d,function(a){return f.compile(a,{delimiters:e}).render(b,c)}),h=f.compile(g.toString(),{delimiters:e}).render(b,c);return this.b=h,!1},b:"",ls:function(a,b,c,d,e,f,g){var h=b[b.length-1],i=null;if(!d&&this.c&&a.length>0)return this.ho(a,h,c,this.text.substring(e,f),g);i=a.call(h);if(typeof i=="function"){if(d)return!0;if(this.c)return this.ho(i,h,c,this.text.substring(e,f),g)}return i},lv:function(a,b,c){var d=b[b.length-1],e=a.call(d);return typeof e=="function"&&(e=e.call(d)),e=e.toString(),this.c&&~e.indexOf("{{")?this.c.compile(e).render(d,c):e}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"}})(typeof exports!="undefined"?exports:Hogan),function(a){function h(a){a.n.substr(a.n.length-1)==="}"&&(a.n=a.n.substring(0,a.n.length-1))}function i(a){return a.trim?a.trim():a.replace(/^\s*|\s*$/g,"")}function j(a,b,c){if(b.charAt(c)!=a.charAt(0))return!1;for(var d=1,e=a.length;d0){g=a.shift();if(g.tag=="#"||g.tag=="^"||l(g,d))c.push(g),g.nodes=k(a,g.tag,c,d),e.push(g);else{if(g.tag=="/"){if(c.length===0)throw new Error("Closing tag without opener: /"+g.n);f=c.pop();if(g.n!=f.n&&!m(g.n,f.n,d))throw new Error("Nesting error: "+f.n+" vs. "+g.n);return f.end=g.i,e}e.push(g)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function l(a,b){for(var c=0,d=b.length;c"?b+=t(a[c]):e=="{"||e=="&"?b+=u(a[c].n,p(a[c].n)):e=="\n"?b+=w('"\\n"'+(a.length-1==c?"":" + i")):e=="_v"?b+=v(a[c].n,p(a[c].n)):e===undefined&&(b+=w('"'+o(a[c])+'"'))}return b}function r(a,b,c,d,e,f){return"if(_.s(_."+c+'("'+o(b)+'",c,p,1),'+"c,p,0,"+d+","+e+', "'+f+'")){'+"b += _.rs(c,p,"+'function(c,p){ var b = "";'+q(a)+"return b;});c.pop();}"+'else{b += _.b; _.b = ""};'}function s(a,b,c){return"if (!_.s(_."+c+'("'+o(b)+'",c,p,1),c,p,1,0,0,"")){'+q(a)+"};"}function t(a){return'b += _.rp("'+o(a.n)+'",c,p,"'+(a.indent||"")+'");'}function u(a,b){return"b += (_."+b+'("'+o(a)+'",c,p,0));'}function v(a,b){return"b += (_.v(_."+b+'("'+o(a)+'",c,p,0)));'}function w(a){return"b += "+a+";"}var b=/\S/,c=/\"/g,d=/\n/g,e=/\r/g,f=/\\/g,g={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10};a.scan=function(c,d){function w(){p.length>0&&(q.push(new String(p)),p="")}function x(){var a=!0;for(var c=t;c"&&(d.indent=q[c].toString()),q.splice(c,1));else b||q.push({tag:"\n"});r=!1,t=q.length}function z(a,b){var c="="+v,d=a.indexOf(c,b),e=i(a.substring(a.indexOf("=",b)+1,d)).split(" ");return u=e[0],v=e[1],d+c.length-1}var e=c.length,f=0,k=1,l=2,m=f,n=null,o=null,p="",q=[],r=!1,s=0,t=0,u="{{",v="}}";d&&(d=d.split(" "),u=d[0],v=d[1]);for(s=0;s=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=this.c,g=a.call(b,d,function(a){return f.compile(a,{delimiters:e}).render(b,c)}),h=f.compile(g.toString(),{delimiters:e}).render(b,c);return this.b=h,!1},b:"",ls:function(a,b,c,d,e,f,g){var h=b[b.length-1],i=null;if(!d&&this.c&&a.length>0)return this.ho(a,h,c,this.text.substring(e,f),g);i=a.call(h);if(typeof i=="function"){if(d)return!0;if(this.c)return this.ho(i,h,c,this.text.substring(e,f),g)}return i},lv:function(a,b,c){var d=b[b.length-1],e=a.call(d);return typeof e=="function"&&(e=e.call(d)),e=e.toString(),this.c&&~e.indexOf("{{")?this.c.compile(e).render(d,c):e}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"}})(typeof exports!="undefined"?exports:Hogan),function(a){function h(a){a.n.substr(a.n.length-1)==="}"&&(a.n=a.n.substring(0,a.n.length-1))}function i(a){return a.trim?a.trim():a.replace(/^\s*|\s*$/g,"")}function j(a,b,c){if(b.charAt(c)!=a.charAt(0))return!1;for(var d=1,e=a.length;d0){g=a.shift();if(g.tag=="#"||g.tag=="^"||l(g,d))c.push(g),g.nodes=k(a,g.tag,c,d),e.push(g);else{if(g.tag=="/"){if(c.length===0)throw new Error("Closing tag without opener: /"+g.n);f=c.pop();if(g.n!=f.n&&!m(g.n,f.n,d))throw new Error("Nesting error: "+f.n+" vs. "+g.n);return f.end=g.i,e}e.push(g)}}if(c.length>0)throw new Error("missing closing tag: "+c.pop().n);return e}function l(a,b){for(var c=0,d=b.length;c"?b+=t(a[c]):e=="{"||e=="&"?b+=u(a[c].n,p(a[c].n)):e=="\n"?b+=w('"\\n"'+(a.length-1==c?"":" + i")):e=="_v"?b+=v(a[c].n,p(a[c].n)):e===undefined&&(b+=w('"'+o(a[c])+'"'))}return b}function r(a,b,c,d,e,f){return"if(_.s(_."+c+'("'+o(b)+'",c,p,1),'+"c,p,0,"+d+","+e+', "'+f+'")){'+"b += _.rs(c,p,"+'function(c,p){ var b = "";'+q(a)+"return b;});c.pop();}"+'else{b += _.b; _.b = ""};'}function s(a,b,c){return"if (!_.s(_."+c+'("'+o(b)+'",c,p,1),c,p,1,0,0,"")){'+q(a)+"};"}function t(a){return'b += _.rp("'+o(a.n)+'",c,p,"'+(a.indent||"")+'");'}function u(a,b){return"b += (_."+b+'("'+o(a)+'",c,p,0));'}function v(a,b){return"b += (_.v(_."+b+'("'+o(a)+'",c,p,0)));'}function w(a){return"b += "+a+";"}var b=/\S/,c=/\"/g,d=/\n/g,e=/\r/g,f=/\\/g,g={"#":1,"^":2,"/":3,"!":4,">":5,"<":6,"=":7,_v:8,"{":9,"&":10};a.scan=function(c,d){function w(){p.length>0&&(q.push(new String(p)),p="")}function x(){var a=!0;for(var c=t;c"&&(d.indent=q[c].toString()),q.splice(c,1));else b||q.push({tag:"\n"});r=!1,t=q.length}function z(a,b){var c="="+v,d=a.indexOf(c,b),e=i(a.substring(a.indexOf("=",b)+1,d)).split(" ");return u=e[0],v=e[1],d+c.length-1}var e=c.length,f=0,k=1,l=2,m=f,n=null,o=null,p="",q=[],r=!1,s=0,t=0,u="{{",v="}}";d&&(d=d.split(" "),u=d[0],v=d[1]);for(s=0;s= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var compiler = this.c; - var t = val.call(cx, text, function(t) { - return compiler.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, inverted, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = null; - - if (!inverted && this.c && val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - t = val.call(cx); - - if (typeof t == 'function') { - if (inverted) { - return true; - } else if (this.c) { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - var result = val.call(cx); - if (typeof result == 'function') { - result = result.call(cx); - } - result = result.toString(); - - if (this.c && ~result.indexOf("{{")) { - return this.c.compile(result).render(cx, partials); - } - - return result; - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String((str === null || str === undefined) ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - -})(typeof exports !== 'undefined' ? exports : Hogan); - - - - -(function (Hogan) { - // Setup regex assignments - // remove whitespace according to Mustache spec - var rIsWhitespace = /\S/, - rQuot = /\"/g, - rNewline = /\n/g, - rCr = /\r/g, - rSlash = /\\/g, - tagTypes = { - '#': 1, '^': 2, '/': 3, '!': 4, '>': 5, - '<': 6, '=': 7, '_v': 8, '{': 9, '&': 10 - }; - - Hogan.scan = function scan(text, delimiters) { - var len = text.length, - IN_TEXT = 0, - IN_TAG_TYPE = 1, - IN_TAG = 2, - state = IN_TEXT, - tagType = null, - tag = null, - buf = '', - tokens = [], - seenTag = false, - i = 0, - lineStart = 0, - otag = '{{', - ctag = '}}'; - - function addBuf() { - if (buf.length > 0) { - tokens.push(new String(buf)); - buf = ''; - } - } - - function lineIsWhitespace() { - var isAllWhitespace = true; - for (var j = lineStart; j < tokens.length; j++) { - isAllWhitespace = - (tokens[j].tag && tagTypes[tokens[j].tag] < tagTypes['_v']) || - (!tokens[j].tag && tokens[j].match(rIsWhitespace) === null); - if (!isAllWhitespace) { - return false; - } - } - - return isAllWhitespace; - } - - function filterLine(haveSeenTag, noNewLine) { - addBuf(); - - if (haveSeenTag && lineIsWhitespace()) { - for (var j = lineStart, next; j < tokens.length; j++) { - if (!tokens[j].tag) { - if ((next = tokens[j+1]) && next.tag == '>') { - // set indent to token value - next.indent = tokens[j].toString() - } - tokens.splice(j, 1); - } - } - } else if (!noNewLine) { - tokens.push({tag:'\n'}); - } - - seenTag = false; - lineStart = tokens.length; - } - - function changeDelimiters(text, index) { - var close = '=' + ctag, - closeIndex = text.indexOf(close, index), - delimiters = trim( - text.substring(text.indexOf('=', index) + 1, closeIndex) - ).split(' '); - - otag = delimiters[0]; - ctag = delimiters[1]; - - return closeIndex + close.length - 1; - } - - if (delimiters) { - delimiters = delimiters.split(' '); - otag = delimiters[0]; - ctag = delimiters[1]; - } - - for (i = 0; i < len; i++) { - if (state == IN_TEXT) { - if (tagChange(otag, text, i)) { - --i; - addBuf(); - state = IN_TAG_TYPE; - } else { - if (text.charAt(i) == '\n') { - filterLine(seenTag); - } else { - buf += text.charAt(i); - } - } - } else if (state == IN_TAG_TYPE) { - i += otag.length - 1; - tag = tagTypes[text.charAt(i + 1)]; - tagType = tag ? text.charAt(i + 1) : '_v'; - if (tagType == '=') { - i = changeDelimiters(text, i); - state = IN_TEXT; - } else { - if (tag) { - i++; - } - state = IN_TAG; - } - seenTag = i; - } else { - if (tagChange(ctag, text, i)) { - tokens.push({tag: tagType, n: trim(buf), otag: otag, ctag: ctag, - i: (tagType == '/') ? seenTag - ctag.length : i + otag.length}); - buf = ''; - i += ctag.length - 1; - state = IN_TEXT; - if (tagType == '{') { - if (ctag == '}}') { - i++; - } else { - cleanTripleStache(tokens[tokens.length - 1]); - } - } - } else { - buf += text.charAt(i); - } - } - } - - filterLine(seenTag, true); - - return tokens; - } - - function cleanTripleStache(token) { - if (token.n.substr(token.n.length - 1) === '}') { - token.n = token.n.substring(0, token.n.length - 1); - } - } - - function trim(s) { - if (s.trim) { - return s.trim(); - } - - return s.replace(/^\s*|\s*$/g, ''); - } - - function tagChange(tag, text, index) { - if (text.charAt(index) != tag.charAt(0)) { - return false; - } - - for (var i = 1, l = tag.length; i < l; i++) { - if (text.charAt(index + i) != tag.charAt(i)) { - return false; - } - } - - return true; - } - - function buildTree(tokens, kind, stack, customTags) { - var instructions = [], - opener = null, - token = null; - - while (tokens.length > 0) { - token = tokens.shift(); - if (token.tag == '#' || token.tag == '^' || isOpener(token, customTags)) { - stack.push(token); - token.nodes = buildTree(tokens, token.tag, stack, customTags); - instructions.push(token); - } else if (token.tag == '/') { - if (stack.length === 0) { - throw new Error('Closing tag without opener: /' + token.n); - } - opener = stack.pop(); - if (token.n != opener.n && !isCloser(token.n, opener.n, customTags)) { - throw new Error('Nesting error: ' + opener.n + ' vs. ' + token.n); - } - opener.end = token.i; - return instructions; - } else { - instructions.push(token); - } - } - - if (stack.length > 0) { - throw new Error('missing closing tag: ' + stack.pop().n); - } - - return instructions; - } - - function isOpener(token, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].o == token.n) { - token.tag = '#'; - return true; - } - } - } - - function isCloser(close, open, tags) { - for (var i = 0, l = tags.length; i < l; i++) { - if (tags[i].c == close && tags[i].o == open) { - return true; - } - } - } - - function writeCode(tree) { - return 'i = i || "";var b = i + "";var _ = this;' + walk(tree) + 'return b;'; - } - - Hogan.generate = function (code, text, options) { - if (options.asString) { - return 'function(c,p,i){' + code + ';}'; - } - - return new Hogan.Template(new Function('c', 'p', 'i', code), text, Hogan); - } - - function esc(s) { - return s.replace(rSlash, '\\\\') - .replace(rQuot, '\\\"') - .replace(rNewline, '\\n') - .replace(rCr, '\\r'); - } - - function chooseMethod(s) { - return (~s.indexOf('.')) ? 'd' : 'f'; - } - - function walk(tree) { - var code = ''; - for (var i = 0, l = tree.length; i < l; i++) { - var tag = tree[i].tag; - if (tag == '#') { - code += section(tree[i].nodes, tree[i].n, chooseMethod(tree[i].n), - tree[i].i, tree[i].end, tree[i].otag + " " + tree[i].ctag); - } else if (tag == '^') { - code += invertedSection(tree[i].nodes, tree[i].n, - chooseMethod(tree[i].n)); - } else if (tag == '<' || tag == '>') { - code += partial(tree[i]); - } else if (tag == '{' || tag == '&') { - code += tripleStache(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag == '\n') { - code += text('"\\n"' + (tree.length-1 == i ? '' : ' + i')); - } else if (tag == '_v') { - code += variable(tree[i].n, chooseMethod(tree[i].n)); - } else if (tag === undefined) { - code += text('"' + esc(tree[i]) + '"'); - } - } - return code; - } - - function section(nodes, id, method, start, end, tags) { - return 'if(_.s(_.' + method + '("' + esc(id) + '",c,p,1),' + - 'c,p,0,' + start + ',' + end + ', "' + tags + '")){' + - 'b += _.rs(c,p,' + - 'function(c,p){ var b = "";' + - walk(nodes) + - 'return b;});c.pop();}' + - 'else{b += _.b; _.b = ""};'; - } - - function invertedSection(nodes, id, method) { - return 'if (!_.s(_.' + method + '("' + esc(id) + '",c,p,1),c,p,1,0,0,"")){' + - walk(nodes) + - '};'; - } - - function partial(tok) { - return 'b += _.rp("' + esc(tok.n) + '",c,p,"' + (tok.indent || '') + '");'; - } - - function tripleStache(id, method) { - return 'b += (_.' + method + '("' + esc(id) + '",c,p,0));'; - } - - function variable(id, method) { - return 'b += (_.v(_.' + method + '("' + esc(id) + '",c,p,0)));'; - } - - function text(id) { - return 'b += ' + id + ';'; - } - - Hogan.parse = function(tokens, options) { - options = options || {}; - return buildTree(tokens, '', [], options.sectionTags || []); - }, - - Hogan.cache = {}; - - Hogan.compile = function(text, options) { - // options - // - // asString: false (default) - // - // sectionTags: [{o: '_foo', c: 'foo'}] - // An array of object with o and c fields that indicate names for custom - // section tags. The example above allows parsing of {{_foo}}{{/foo}}. - // - // delimiters: A string that overrides the default delimiters. - // Example: "<% %>" - // - options = options || {}; - - var key = text + '||' + !!options.asString; - - var t = this.cache[key]; - - if (t) { - return t; - } - - t = this.generate(writeCode(this.parse(this.scan(text, options.delimiters), options)), text, options); - return this.cache[key] = t; - }; -})(typeof exports !== 'undefined' ? exports : Hogan); - - -var Mustache = (function (Hogan) { - - // Mustache.js has non-spec partial context behavior - function mustachePartial(name, context, partials, indent) { - var partialScope = this.f(name, context, partials, 0); - var cx = context; - if (partialScope) { - cx = cx.concat(partialScope); - } - - return Hogan.Template.prototype.rp.call(this, name, cx, partials, indent); - } - - var HoganTemplateWrapper = function(renderFunc, text, compiler){ - this.rp = mustachePartial; - Hogan.Template.call(this, renderFunc, text, compiler); - }; - HoganTemplateWrapper.prototype = Hogan.Template.prototype; - - // Add a wrapper for Hogan's generate method. Mustache and Hogan keep - // separate caches, and Mustache returns wrapped templates. - var wrapper; - var HoganWrapper = function(){ - this.cache = {}; - this.generate = function(code, text, options) { - return new HoganTemplateWrapper(new Function('c', 'p', 'i', code), text, wrapper); - } - }; - HoganWrapper.prototype = Hogan; - wrapper = new HoganWrapper(); - - return { - to_html: function(text, data, partials, sendFun) { - var template = wrapper.compile(text); - var result = template.render(data, partials); - if (!sendFun) { - return result; - } - - sendFun(result); - } - } - -})(Hogan); diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/template-1.0.5.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/template-1.0.5.js deleted file mode 100644 index 8958a70..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/template-1.0.5.js +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var Hogan = {}; - -(function (Hogan) { - Hogan.Template = function constructor(renderFunc, text, compiler) { - if (renderFunc) { - this.r = renderFunc; - } - this.c = compiler; - this.text = text || ''; - } - - Hogan.Template.prototype = { - // render: replaced by generated code. - r: function (context, partials, indent) { return ''; }, - - // variable escaping - v: hoganEscape, - - render: function render(context, partials, indent) { - return this.ri([context], partials || {}, indent); - }, - - // render internal -- a hook for overrides that catches partials too - ri: function (context, partials, indent) { - return this.r(context, partials, indent); - }, - - // tries to find a partial in the curent scope and render it - rp: function(name, context, partials, indent) { - var partial = partials[name]; - - if (!partial) { - return ''; - } - - if (this.c && typeof partial == 'string') { - partial = this.c.compile(partial); - } - - return partial.ri(context, partials, indent); - }, - - // render a section - rs: function(context, partials, section) { - var buf = '', - tail = context[context.length - 1]; - - if (!isArray(tail)) { - return buf = section(context, partials); - } - - for (var i = 0; i < tail.length; i++) { - context.push(tail[i]); - buf += section(context, partials); - context.pop(); - } - - return buf; - }, - - // maybe start a section - s: function(val, ctx, partials, inverted, start, end, tags) { - var pass; - - if (isArray(val) && val.length === 0) { - return false; - } - - if (typeof val == 'function') { - val = this.ls(val, ctx, partials, inverted, start, end, tags); - } - - pass = (val === '') || !!val; - - if (!inverted && pass && ctx) { - ctx.push((typeof val == 'object') ? val : ctx[ctx.length - 1]); - } - - return pass; - }, - - // find values with dotted names - d: function(key, ctx, partials, returnFound) { - var names = key.split('.'), - val = this.f(names[0], ctx, partials, returnFound), - cx = null; - - if (key === '.' && isArray(ctx[ctx.length - 2])) { - return ctx[ctx.length - 1]; - } - - for (var i = 1; i < names.length; i++) { - if (val && typeof val == 'object' && names[i] in val) { - cx = val; - val = val[names[i]]; - } else { - val = ''; - } - } - - if (returnFound && !val) { - return false; - } - - if (!returnFound && typeof val == 'function') { - ctx.push(cx); - val = this.lv(val, ctx, partials); - ctx.pop(); - } - - return val; - }, - - // find values with normal names - f: function(key, ctx, partials, returnFound) { - var val = false, - v = null, - found = false; - - for (var i = ctx.length - 1; i >= 0; i--) { - v = ctx[i]; - if (v && typeof v == 'object' && key in v) { - val = v[key]; - found = true; - break; - } - } - - if (!found) { - return (returnFound) ? false : ""; - } - - if (!returnFound && typeof val == 'function') { - val = this.lv(val, ctx, partials); - } - - return val; - }, - - // higher order templates - ho: function(val, cx, partials, text, tags) { - var compiler = this.c; - var t = val.call(cx, text, function(t) { - return compiler.compile(t, {delimiters: tags}).render(cx, partials); - }); - var s = compiler.compile(t.toString(), {delimiters: tags}).render(cx, partials); - this.b = s; - return false; - }, - - // higher order template result buffer - b: '', - - // lambda replace section - ls: function(val, ctx, partials, inverted, start, end, tags) { - var cx = ctx[ctx.length - 1], - t = null; - - if (!inverted && this.c && val.length > 0) { - return this.ho(val, cx, partials, this.text.substring(start, end), tags); - } - - t = val.call(cx); - - if (typeof t == 'function') { - if (inverted) { - return true; - } else if (this.c) { - return this.ho(t, cx, partials, this.text.substring(start, end), tags); - } - } - - return t; - }, - - // lambda replace variable - lv: function(val, ctx, partials) { - var cx = ctx[ctx.length - 1]; - var result = val.call(cx); - if (typeof result == 'function') { - result = result.call(cx); - } - result = result.toString(); - - if (this.c && ~result.indexOf("{{")) { - return this.c.compile(result).render(cx, partials); - } - - return result; - } - - }; - - var rAmp = /&/g, - rLt = //g, - rApos =/\'/g, - rQuot = /\"/g, - hChars =/[&<>\"\']/; - - function hoganEscape(str) { - str = String((str === null || str === undefined) ? '' : str); - return hChars.test(str) ? - str - .replace(rAmp,'&') - .replace(rLt,'<') - .replace(rGt,'>') - .replace(rApos,''') - .replace(rQuot, '"') : - str; - } - - var isArray = Array.isArray || function(a) { - return Object.prototype.toString.call(a) === '[object Array]'; - }; - -})(typeof exports !== 'undefined' ? exports : Hogan); - diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/template-1.0.5.min.js b/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/template-1.0.5.min.js deleted file mode 100644 index 4ec5796..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/builds/1.0.5/template-1.0.5.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/** -* @preserve Copyright 2012 Twitter, Inc. -* @license http://www.apache.org/licenses/LICENSE-2.0.txt -*/ -var Hogan={};(function(a){function h(a){return a=String(a===null||a===undefined?"":a),g.test(a)?a.replace(b,"&").replace(c,"<").replace(d,">").replace(e,"'").replace(f,"""):a}a.Template=function j(a,b,c){a&&(this.r=a),this.c=c,this.text=b||""},a.Template.prototype={r:function(a,b,c){return""},v:h,render:function(b,c,d){return this.ri([b],c||{},d)},ri:function(a,b,c){return this.r(a,b,c)},rp:function(a,b,c,d){var e=c[a];return e?(this.c&&typeof e=="string"&&(e=this.c.compile(e)),e.ri(b,c,d)):""},rs:function(a,b,c){var d="",e=a[a.length-1];if(!i(e))return d=c(a,b);for(var f=0;f=0;h--){f=b[h];if(f&&typeof f=="object"&&a in f){e=f[a],g=!0;break}}return g?(!d&&typeof e=="function"&&(e=this.lv(e,b,c)),e):d?!1:""},ho:function(a,b,c,d,e){var f=this.c,g=a.call(b,d,function(a){return f.compile(a,{delimiters:e}).render(b,c)}),h=f.compile(g.toString(),{delimiters:e}).render(b,c);return this.b=h,!1},b:"",ls:function(a,b,c,d,e,f,g){var h=b[b.length-1],i=null;if(!d&&this.c&&a.length>0)return this.ho(a,h,c,this.text.substring(e,f),g);i=a.call(h);if(typeof i=="function"){if(d)return!0;if(this.c)return this.ho(i,h,c,this.text.substring(e,f),g)}return i},lv:function(a,b,c){var d=b[b.length-1],e=a.call(d);return typeof e=="function"&&(e=e.call(d)),e=e.toString(),this.c&&~e.indexOf("{{")?this.c.compile(e).render(d,c):e}};var b=/&/g,c=//g,e=/\'/g,f=/\"/g,g=/[&<>\"\']/,i=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"}})(typeof exports!="undefined"?exports:Hogan) \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/favicon.ico b/public/bootstrap/docs/build/node_modules/hogan.js/web/favicon.ico deleted file mode 100644 index 627ee83..0000000 Binary files a/public/bootstrap/docs/build/node_modules/hogan.js/web/favicon.ico and /dev/null differ diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/logo.png b/public/bootstrap/docs/build/node_modules/hogan.js/web/images/logo.png deleted file mode 100644 index d25879d..0000000 Binary files a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/logo.png and /dev/null differ diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/noise.png b/public/bootstrap/docs/build/node_modules/hogan.js/web/images/noise.png deleted file mode 100644 index 99ce757..0000000 Binary files a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/noise.png and /dev/null differ diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/small-hogan-icon.png b/public/bootstrap/docs/build/node_modules/hogan.js/web/images/small-hogan-icon.png deleted file mode 100644 index 0558ef1..0000000 Binary files a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/small-hogan-icon.png and /dev/null differ diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/stripes.png b/public/bootstrap/docs/build/node_modules/hogan.js/web/images/stripes.png deleted file mode 100644 index adf332d..0000000 Binary files a/public/bootstrap/docs/build/node_modules/hogan.js/web/images/stripes.png and /dev/null differ diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/index.html.mustache b/public/bootstrap/docs/build/node_modules/hogan.js/web/index.html.mustache deleted file mode 100755 index 75fcbfb..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/index.html.mustache +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - Hogan.js - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    -

    Hogan.js

    -

    JavaScript templating from Twitter.

    - View on Github -
    -
    -
    - - -
    -

    Getting started

    -

    - Hogan.js is a 2.5k JS templating engine developed at Twitter. Use it as a part of your asset packager to compile templates ahead of time or include it in your browser to handle dynamic templates. -

    -

    - If you're developing with Node.js, just use NPM to add the Hogan package. -

    -
    $ npm install hogan.js
    -

    - Alternatively, drop hogan.js in your browser by adding the following script. -

    -
    <script src="http://twitter.github.com/hogan.js/builds/{{version}}/hogan.js"></script>
    - -
    -
    - -
    -
    -
    -
    - - -
    -

    Templates

    -

    - Hogan.js was developed against the mustache test suite, so everything that holds true for templates as specified here, is also the case for hogan.js. -

    -

    - That means you get variables, sections, lambdas, partials, filters, and everything else you've come to expect from mustache templating - only much, much faster. -

    -
    -
    - -
    -
    -
    -
    - - -
    -

    Compiling

    -

    - Use hogan.compile() to precompile your templates into vanilla JS. -

    -

    - It's best to serve your templates precompiled whenever you can (rather than the raw templates), as parsing is the most time consuming operation. -

    -

    -

    -
    -
    - -
    -
    -
    -
    - - -
    -

    Rendering

    -

    - Once compiled, call the render() method with a context and optional partials object. -

    -

    - If supplying partials, you can compile them ahead of time, or pass string templates.

    -

    -

    -
    -
    - -
    - - - - - -
    - - - - - diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/stylesheets/layout.css b/public/bootstrap/docs/build/node_modules/hogan.js/web/stylesheets/layout.css deleted file mode 100755 index c9e3e35..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/stylesheets/layout.css +++ /dev/null @@ -1,206 +0,0 @@ - - -/* #Reset & Basics (Inspired by E. Meyers) -================================================== */ - html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; } - article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { - display: block; } - body { - line-height: 1; } - ol, ul { - list-style: none; } - blockquote, q { - quotes: none; } - blockquote:before, blockquote:after, - q:before, q:after { - content: ''; - content: none; } - table { - border-collapse: collapse; - border-spacing: 0; } - - -/* #Basic Styles -================================================== */ - body { - background: #fff; - font: 14px/24px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; - color: #000; - -webkit-font-smoothing: antialiased; /* Fix for webkit rendering */ - -webkit-text-size-adjust: 100%; - } - a { - color: #999113; - text-decoration: none; - } - a:hover { - color: #7b750e; - text-decoration: underline; - } - - -/* #Typography -================================================== */ - h1, h2, h3, h4, h5, h6 { - font-weight: bold; } - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; } - h1 { font-size: 75px; line-height: 80px; margin-bottom: 14px;} - h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; } - h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; } - h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; } - h5 { font-size: 17px; line-height: 24px; } - h6 { font-size: 14px; line-height: 21px; } - p { margin-bottom: 22px; } - - -/* #Main styles -================================================== */ - -/* Hogan Hero */ -.hogan-hero { - position: relative; - background: #333; /* Old browsers */ - background: -moz-radial-gradient(center, ellipse cover, #333 0%, #000 100%); /* FF3.6+ */ - background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#333), color-stop(100%,#000)); /* Chrome,Safari4+ */ - background: -webkit-radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* Chrome10+,Safari5.1+ */ - background: -o-radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* Opera 12+ */ - background: -ms-radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* IE10+ */ - background: radial-gradient(center, ellipse cover, #333 0%,#000 100%); /* W3C */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#333', endColorstr='#000',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ -} -.hogan-hero .container { - padding: 180px 0; -} -.hogan-hero h1 { - letter-spacing: -3px; - color: #fff; - position: relative; - margin-bottom: 5px; -} -.hogan-hero h3 { - max-width: 650px; - margin-bottom: 20px; - color: #fff; -} -.hogan-hero .noise, -.hogan-hero .stripes { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; -} -.hogan-hero .noise { - background: url(../images/noise.png) repeat; -} -.hogan-hero .stripes { - background: url(../images/stripes.png) repeat; -} - -/* Primary content container */ -.primary.container { - padding-top: 100px; -} - -/*Hogan divider */ -.hogan-divider { - padding-top: 60px; - border-bottom: 1px solid #ddd; - margin-bottom: 60px; - clear: both; - position: relative; -} -.hogan-icon { - width: 40px; - height: 30px; - position: absolute; - left: 50%; - top: 46px; - margin-left: -20px; - background: url('../images/small-hogan-icon.png') white no-repeat center center; -} - -/* Button style */ -.button { - display: inline-block; - cursor: pointer; - background: #dfd52e; - border-radius: 3px; - margin-bottom: 20px; - color: #000; - text-transform: uppercase; - text-decoration: none; - font-size: 15px; - padding: 0 34px; - line-height: 46px; - font-weight: bold; - -webkit-transition: background-color .3s ease-in-out; - -moz-transition: background-color .3s ease-in-out; - transition: background-color .3s ease-in-out; - -} -.button:hover { - text-decoration: inherit; - color: inherit; - background-color: #f5e810; -} - -/* Hogan footer */ -.hogan-footer { - border-top: 1px solid #ddd; - margin-top: 60px; - padding: 20px 0 40px; - color: #999; - font-size: 12px; -} -.hogan-footer .copyright { - float: left; -} -.hogan-footer .colophon { - float: right; -} - -pre, code { - background: #F8F8FF; - border: 1px solid #DDD; - padding: 5px 10px; - margin-bottom: 20px; - font-family: courier; - overflow: hidden; -} - -pre code { - border: 0; - padding: 0; - margin-bottom: 0; -} - - -/* #Media Queries -================================================== */ - - /* Smaller than standard 960 (devices and browsers) */ - @media only screen and (max-width: 959px) {} - - /* Tablet Portrait size to standard 960 (devices and browsers) */ - @media only screen and (min-width: 768px) and (max-width: 959px) {} - - /* All Mobile Sizes (devices and browser) */ - @media only screen and (max-width: 767px) { - .hogan-hero .container { - padding: 100px 0; - } - } - - /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ - @media only screen and (min-width: 480px) and (max-width: 767px) {} - - /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ - @media only screen and (max-width: 479px) {} - diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/web/stylesheets/skeleton.css b/public/bootstrap/docs/build/node_modules/hogan.js/web/stylesheets/skeleton.css deleted file mode 100755 index d0264a4..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/web/stylesheets/skeleton.css +++ /dev/null @@ -1,236 +0,0 @@ -/* -* Skeleton V1.1 -* Copyright 2011, Dave Gamache -* www.getskeleton.com -* Free to use under the MIT license. -* http://www.opensource.org/licenses/mit-license.php -* 8/17/2011 -*/ - - -/* Table of Contents -================================================== - #Base 960 Grid - #Tablet (Portrait) - #Mobile (Portrait) - #Mobile (Landscape) - #Clearing */ - - - -/* #Base 960 Grid -================================================== */ - - .container { position: relative; width: 960px; margin: 0 auto; padding: 0; } - .column, .columns { float: left; display: inline; margin-left: 10px; margin-right: 10px; } - .row { margin-bottom: 20px; } - - /* Nested Column Classes */ - .column.alpha, .columns.alpha { margin-left: 0; } - .column.omega, .columns.omega { margin-right: 0; } - - /* Base Grid */ - .container .one.column { width: 40px; } - .container .two.columns { width: 100px; } - .container .three.columns { width: 160px; } - .container .four.columns { width: 220px; } - .container .five.columns { width: 280px; } - .container .six.columns { width: 340px; } - .container .seven.columns { width: 400px; } - .container .eight.columns { width: 460px; } - .container .nine.columns { width: 520px; } - .container .ten.columns { width: 580px; } - .container .eleven.columns { width: 640px; } - .container .twelve.columns { width: 700px; } - .container .thirteen.columns { width: 760px; } - .container .fourteen.columns { width: 820px; } - .container .fifteen.columns { width: 880px; } - .container .sixteen.columns { width: 940px; } - - .container .one-third.column { width: 300px; } - .container .two-thirds.column { width: 620px; } - - /* Offsets */ - .container .offset-by-one { padding-left: 60px; } - .container .offset-by-two { padding-left: 120px; } - .container .offset-by-three { padding-left: 180px; } - .container .offset-by-four { padding-left: 240px; } - .container .offset-by-five { padding-left: 300px; } - .container .offset-by-six { padding-left: 360px; } - .container .offset-by-seven { padding-left: 420px; } - .container .offset-by-eight { padding-left: 480px; } - .container .offset-by-nine { padding-left: 540px; } - .container .offset-by-ten { padding-left: 600px; } - .container .offset-by-eleven { padding-left: 660px; } - .container .offset-by-twelve { padding-left: 720px; } - .container .offset-by-thirteen { padding-left: 780px; } - .container .offset-by-fourteen { padding-left: 840px; } - .container .offset-by-fifteen { padding-left: 900px; } - - - -/* #Tablet (Portrait) -================================================== */ - - /* Note: Design for a width of 768px */ - - @media only screen and (min-width: 768px) and (max-width: 959px) { - .container { width: 768px; } - .container .column, - .container .columns { margin-left: 10px; margin-right: 10px; } - .column.alpha, .columns.alpha { margin-left: 0; margin-right: 10px; } - .column.omega, .columns.omega { margin-right: 0; margin-left: 10px; } - - .container .one.column { width: 28px; } - .container .two.columns { width: 76px; } - .container .three.columns { width: 124px; } - .container .four.columns { width: 172px; } - .container .five.columns { width: 220px; } - .container .six.columns { width: 268px; } - .container .seven.columns { width: 316px; } - .container .eight.columns { width: 364px; } - .container .nine.columns { width: 412px; } - .container .ten.columns { width: 460px; } - .container .eleven.columns { width: 508px; } - .container .twelve.columns { width: 556px; } - .container .thirteen.columns { width: 604px; } - .container .fourteen.columns { width: 652px; } - .container .fifteen.columns { width: 700px; } - .container .sixteen.columns { width: 748px; } - - .container .one-third.column { width: 236px; } - .container .two-thirds.column { width: 492px; } - - /* Offsets */ - .container .offset-by-one { padding-left: 48px; } - .container .offset-by-two { padding-left: 96px; } - .container .offset-by-three { padding-left: 144px; } - .container .offset-by-four { padding-left: 192px; } - .container .offset-by-five { padding-left: 240px; } - .container .offset-by-six { padding-left: 288px; } - .container .offset-by-seven { padding-left: 336px; } - .container .offset-by-eight { padding-left: 348px; } - .container .offset-by-nine { padding-left: 432px; } - .container .offset-by-ten { padding-left: 480px; } - .container .offset-by-eleven { padding-left: 528px; } - .container .offset-by-twelve { padding-left: 576px; } - .container .offset-by-thirteen { padding-left: 624px; } - .container .offset-by-fourteen { padding-left: 672px; } - .container .offset-by-fifteen { padding-left: 720px; } - } - - -/* #Mobile (Portrait) -================================================== */ - - /* Note: Design for a width of 320px */ - - @media only screen and (max-width: 767px) { - .container { width: 300px; } - .columns, .column { margin: 0; } - - .container .one.column, - .container .two.columns, - .container .three.columns, - .container .four.columns, - .container .five.columns, - .container .six.columns, - .container .seven.columns, - .container .eight.columns, - .container .nine.columns, - .container .ten.columns, - .container .eleven.columns, - .container .twelve.columns, - .container .thirteen.columns, - .container .fourteen.columns, - .container .fifteen.columns, - .container .sixteen.columns, - .container .one-third.column, - .container .two-thirds.column { width: 300px; } - - /* Offsets */ - .container .offset-by-one, - .container .offset-by-two, - .container .offset-by-three, - .container .offset-by-four, - .container .offset-by-five, - .container .offset-by-six, - .container .offset-by-seven, - .container .offset-by-eight, - .container .offset-by-nine, - .container .offset-by-ten, - .container .offset-by-eleven, - .container .offset-by-twelve, - .container .offset-by-thirteen, - .container .offset-by-fourteen, - .container .offset-by-fifteen { padding-left: 0; } - - } - - -/* #Mobile (Landscape) -================================================== */ - - /* Note: Design for a width of 480px */ - - @media only screen and (min-width: 480px) and (max-width: 767px) { - .container { width: 420px; } - .columns, .column { margin: 0; } - - .container .one.column, - .container .two.columns, - .container .three.columns, - .container .four.columns, - .container .five.columns, - .container .six.columns, - .container .seven.columns, - .container .eight.columns, - .container .nine.columns, - .container .ten.columns, - .container .eleven.columns, - .container .twelve.columns, - .container .thirteen.columns, - .container .fourteen.columns, - .container .fifteen.columns, - .container .sixteen.columns, - .container .one-third.column, - .container .two-thirds.column { width: 420px; } - } - - -/* #Clearing -================================================== */ - - /* Self Clearing Goodness */ - .container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; } - - /* Use clearfix class on parent to clear nested columns, - or wrap each row of columns in a
    */ - .clearfix:before, - .clearfix:after, - .row:before, - .row:after { - content: '\0020'; - display: block; - overflow: hidden; - visibility: hidden; - width: 0; - height: 0; } - .row:after, - .clearfix:after { - clear: both; } - .row, - .clearfix { - zoom: 1; } - - /* You can also use a
    to clear columns */ - .clear { - clear: both; - display: block; - overflow: hidden; - visibility: hidden; - width: 0; - height: 0; - } - - diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/amd.js.mustache b/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/amd.js.mustache deleted file mode 100644 index d91ef77..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/amd.js.mustache +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -{{{template}}} -{{{compiler}}} - -if (typeof define === 'function' && define.amd) { - define(Hogan); -} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/common.js.mustache b/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/common.js.mustache deleted file mode 100644 index e823e83..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/common.js.mustache +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -{{{template}}} -{{{compiler}}} - -if (typeof module !== 'undefined' && module.exports) { - module.exports = Hogan; -} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/js.mustache b/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/js.mustache deleted file mode 100644 index 9f311f0..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/js.mustache +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -{{{template}}} -{{{compiler}}} diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/mustache.js.mustache b/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/mustache.js.mustache deleted file mode 100644 index d3a3d70..0000000 --- a/public/bootstrap/docs/build/node_modules/hogan.js/wrappers/mustache.js.mustache +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2011 Twitter, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// A wrapper for compatibility with Mustache.js, quirks and all - -{{{template}}} -{{{compiler}}} - -var Mustache = (function (Hogan) { - - // Mustache.js has non-spec partial context behavior - function mustachePartial(name, context, partials, indent) { - var partialScope = this.f(name, context, partials, 0); - var cx = context; - if (partialScope) { - cx = cx.concat(partialScope); - } - - return Hogan.Template.prototype.rp.call(this, name, cx, partials, indent); - } - - var HoganTemplateWrapper = function(renderFunc, text, compiler){ - this.rp = mustachePartial; - Hogan.Template.call(this, renderFunc, text, compiler); - }; - HoganTemplateWrapper.prototype = Hogan.Template.prototype; - - // Add a wrapper for Hogan's generate method. Mustache and Hogan keep - // separate caches, and Mustache returns wrapped templates. - var wrapper; - var HoganWrapper = function(){ - this.cache = {}; - this.generate = function(code, text, options) { - return new HoganTemplateWrapper(new Function('c', 'p', 'i', code), text, wrapper); - } - }; - HoganWrapper.prototype = Hogan; - wrapper = new HoganWrapper(); - - return { - to_html: function(text, data, partials, sendFun) { - var template = wrapper.compile(text); - var result = template.render(data, partials); - if (!sendFun) { - return result; - } - - sendFun(result); - } - } - -})(Hogan); diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..dab59d6 --- /dev/null +++ b/test/README.md @@ -0,0 +1,3 @@ +OpenBook +======== +This is a class project **clone** of *Facebook*. diff --git a/test/app/controllers/AlbumController.java b/test/app/controllers/AlbumController.java new file mode 100644 index 0000000..876fc04 --- /dev/null +++ b/test/app/controllers/AlbumController.java @@ -0,0 +1,168 @@ +/**AlbumController + * purpose: controls all actions associated with an Alb + * + * created by: Chris. Cale + * + * email: collegeassignment@gmail.com + * + */ + +package controllers; + +import java.util.*; + +import play.*; +import play.data.validation.Required; +import play.mvc.*; +import controllers.Secure; +import models.*; + + +public class AlbumController extends OBController{ + + /**create + * + * @param title of new album + * + * @return saves new album into database + */ + public static void create(String title)//@Required(message = "A title is required") + { + Album newAlbum = new Album(title, Application.user()); + newAlbum.save(); + } + + /**delete + * + * @param Id of album + * + * @return none + */ + public static void delete(Long Id){ + Album album = Album.findById(Id); + album.delete(); + //redirect("/album"); + } + + /**getAlbum + * + * @param Id of album + * + * @return renders album to page + */ + public static void getAlbum(Long Id){ + Album album = Album.findById(Id); + if(album == null){ + notFound(); + } + else{ + // response.setContentTypeIfNotSet(album.image.type()); + // renderBinary(album.image.get()); + } + + } + + + /**addPhoto + * + * @param Long Id of album + * @param String title + * @return returns true if the name of album has changed + */ + public static boolean changeTitle(Long Id, String newTitle){ + + Album album = Album.findById(Id); + String oldTitle = album.title; + album.title = newTitle; + //updateDate(album.albumId); + return oldTitle != newTitle; + } + + /**addPhotoToAlbum + * + * @param Long albumId + * @param Long photoId + * @return boolean if photo was added to album + */ + public static boolean addPhotoToAlbum(Long albumId, Long photoId){ + + Album album = Album.findById(albumId); + Photo photo = Photo.findById(photoId); + int oldSize = album.photos.size(); + album.photos.add(photo); + int newSize = album.photos.size(); + //updateDate(album.albumId); + return newSize != oldSize; + } + + + /**deletePhotoFromAlbum + * + * @param albumId + * @param photoId + * @return boolean true if photo is deleted from album + */ + public static boolean deletePhotoFromAlbum(Long albumId, Long photoId){ + + Album album = Album.findById(albumId); + Photo photo = Photo.findById(photoId); + int oldSize = album.photos.size(); + album.photos.remove(photo); + int newSize = album.photos.size(); + //updateDate(album.albumId); + return newSize != oldSize; + } + + /**updateDate + * + * @param Id + * @return boolean true if dateModified has changed + */ + public static boolean updateDate(Long Id){ + Album album = Album.findById(Id); + Date oldDate = album.lastDateModified; + Date date = new Date(); + album.lastDateModified = date; + return oldDate != album.lastDateModified; + } + + /**getAll + * + * @return a list of all albums + */ + public static List getAll(){ + return Album.findAll();// no idea how this works??? + } + + + /**getNext + * + * @param albumId + * @param index + * @return photo at current index + 1 + */ + public static Photo getNext(Long albumId, int index){ + Album album = Album.findById(albumId); + Photo nextPhoto = album.photos.get(index + 1); + return nextPhoto; + } + + /**getPrev + * + * @param albumId + * @param index + * @return photo at current index -1 + */ + public static Photo getPrev(Long albumId, int index){ + Album album = Album.findById(albumId); + Photo nextPhoto = album.photos.get(index - 1); + return nextPhoto; + } + + + //TODO: finish this method + public static void export(){ + System.out.println("TO BE COMPLETED: EXPORT FUNCTIONALITY"); + } +}//end of class + diff --git a/test/app/controllers/Answers.java b/test/app/controllers/Answers.java new file mode 100644 index 0000000..651ecb4 --- /dev/null +++ b/test/app/controllers/Answers.java @@ -0,0 +1,21 @@ +package controllers; + +import models.Answer; + +public class Answers extends OBController { + + public static void chooseAnswer(Long answerId){ + Answer answer = Answer.findById(answerId); + if(answer == null) + notFound(); + answer.addUserChoice(user()); + redirect("/"); + } + + public static void answers(Long answerId){ + Answer answer = Answer.findById(answerId); + if(answer == null) + notFound(); + render(user(), answer); + } +} diff --git a/test/app/controllers/Application.java b/test/app/controllers/Application.java new file mode 100644 index 0000000..683ee5f --- /dev/null +++ b/test/app/controllers/Application.java @@ -0,0 +1,97 @@ +package controllers; + +import java.util.*; + +import org.elasticsearch.index.query.QueryBuilders; + +import play.*; +import play.modules.elasticsearch.ElasticSearch; +import play.modules.elasticsearch.search.SearchResults; +import play.mvc.*; +import controllers.Secure; +import models.*; +import play.libs.Crypto; + + +public class Application extends OBController { + public static void news(Long userId) { + User user = userId == null ? user() : (User) User.findById(userId); + render(user); + } + + public static void account() { + User user = user(); + render(user); + } + + private static boolean given(String val) { + return val != null && val.length() > 0; + } + + + /** + * Create a timeline for the current user + * @param id user ID + */ + public static void createTimeline(Long id){ + User user = User.findById(id); + user.createTimeline(); + renderTemplate("Timeline/Timeline.html",user); + } + + public static void account_save(User update, String old_password) { + User currentUser = user(); + + validation.required(update.first_name).message("First name is required"); + validation.required(update.username).message("Username is required"); + validation.required(update.email).message("Email is required"); + validation.isTrue(currentUser.password.equals(Crypto.passwordHash(old_password))).message("Password does not match"); + + if (validation.hasErrors()) { + User user = update; + renderTemplate("Application/account.html", user); + } else { + User user = currentUser; + String name = ""; + if (given(update.first_name)) { + user.first_name = update.first_name; + name += user.first_name; + } + if (given(update.middle_name)) { + user.middle_name = update.middle_name; + if (given(name)) + name += " "; + name += user.middle_name; + } + if (given(update.last_name)) { + user.last_name = update.last_name; + if (given(name)) + name += " "; + name += user.last_name; + } + user.name = name; + user.username = update.username; + user.email = update.email; + if (given(update.password)) + user.password = Crypto.passwordHash(update.password); + user.save(); + account(); + } + } + + public static void search(String query) { + // not implemented yet + } + + public static void deleteComment(Long id, Long userId) { + Comment c = Comment.findById(id); + c.delete(); + news(userId); + } + + public static void postComment(Long commentableId, String author, String content) { + Commentable parent = Commentable.findById(commentableId); + User au = User.find("email = ?", author).first(); + parent.addComment(au, content); + } +} \ No newline at end of file diff --git a/test/app/controllers/Categories.java b/test/app/controllers/Categories.java new file mode 100644 index 0000000..8945096 --- /dev/null +++ b/test/app/controllers/Categories.java @@ -0,0 +1,54 @@ +package controllers; + +import play.*; +import play.mvc.*; +import play.data.validation.*; +import play.libs.*; +import play.cache.*; +import models.*; + +import java.util.*; + +import javax.persistence.*; + +public class Categories extends OBController { + final static int MAX_CATEGORIES = 8; + + + public static void listAll() { + List Categories = Category.find("order by name").fetch(); + long nextId = 1; + + Iterator iterator = Categories.iterator(); + + while (iterator.hasNext()) + { + Category cat = iterator.next(); + nextId = cat.id; + } + + + render(Categories, nextId); + } + + public static void listSingle(Long catId) { + User _user = Application.user(); + Category category = Category.findById(catId); + List FThreads = FThread.find("category = ? order by postedAt desc", category).fetch(10); + render(FThreads, category, _user); + } + + public static void newCategory (String name, String description) { + final Category category; + if (Category.findAll().size() < MAX_CATEGORIES) + { + category = new Category(name, description).save(); + renderJSON(category.id); + } + } + + public static void deleteCategory (Long categoryId) { + Category c = Category.findById(categoryId); + c.delete(); + } +} diff --git a/test/app/controllers/Checkins.java b/test/app/controllers/Checkins.java new file mode 100644 index 0000000..3548802 --- /dev/null +++ b/test/app/controllers/Checkins.java @@ -0,0 +1,30 @@ +package controllers; + +import java.util.*; + +import controllers.Secure; + +import play.*; +import play.data.validation.Required; +import play.mvc.*; +import play.utils.HTML; +import controllers.Secure; +import models.*; + +public class Checkins extends OBController { + + public static void checkin() { + render(); + } + + public static void at(String location, String name, String address) { + if (location != null && name != null && address != null + && !location.equals("") && !name.equals("") && !address.equals("")) { + new Checkin(user(), user(), location, name, address).save(); + Application.news(null); + } + else { + redirect("/checkin"); + } + } +} diff --git a/test/app/controllers/Comments.java b/test/app/controllers/Comments.java new file mode 100644 index 0000000..5d8a5b6 --- /dev/null +++ b/test/app/controllers/Comments.java @@ -0,0 +1,63 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.db.jpa.*; +import play.mvc.*; + +import models.*; + +public class Comments extends OBController { + public static void comments(Long statusId) { + User user = user(); + List comments; + if (statusId == null) + comments = Comment.findAll(); + else { + Commentable c = Commentable.findById(statusId); + if (c == null) + notFound(); + comments = Comment.find("byParentObj", c).fetch(); + } + render(user, comments); + } + + //comments(Long id): will render the user being viewed unless it is a null user then it will render the current user + public static void userComments(Long userId) { + User user = userId == null ? Application.user() : (User) User.findById(userId); + List comments; + if (userId == null) + comments = Comment.findAll(); + else + comments = user.comments(); + render(user, comments); + } + + public static void comment(Long commentId) { + User user = user(); + Comment comment = Comment.findById(commentId); + if(comment == null) + notFound("That comment does not exist."); + render(user, comment); + } + + public static void deleteComment(Long commentId) { + Comment c = Comment.findById(commentId); + if (c == null) + notFound("That comment does not exist."); + c.delete(); + ok(); + } + + public static void addComment(Long statusId, String content) { + if (content == null) + error("content can't be null"); + final Commentable cc = Commentable.findById(statusId); + if(cc == null) + notFound(statusId + " is not the id of a Commentable"); + final User user = user(); + final Comment comment = new Comment(cc, user, content).save(); + render(user, comment); + } +} \ No newline at end of file diff --git a/test/app/controllers/Events.java b/test/app/controllers/Events.java new file mode 100644 index 0000000..5629e3e --- /dev/null +++ b/test/app/controllers/Events.java @@ -0,0 +1,224 @@ +package controllers; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +import models.Event; +import models.Post; +import models.User; + +public class Events extends OBController { + + public static void event(Long eventId) { + Event event = Event.findById(eventId); + if(event == null) + notFound("That event does not exist."); + String dateString = convertDateToString(event.startDate); + User user = user(); + + String privacy = ""; + if(event.open){ privacy = "Public Event"; } + else if(event.friends){ privacy = "Friends Event"; } + else { privacy = "Invite Only Event"; } + + if (event.givenEndDate){ + // Check to see if the month and day are the same. + DateFormat df = new SimpleDateFormat("MMdd"); + dateString += " until "; + if (df.format(event.startDate).equals(df.format(event.endDate))) + dateString += convertDateTime(event.endDate); + else + dateString += convertDateToString(event.endDate); + } + render(event, user, privacy, dateString); + } + + public static void events(Long userId) { + User user = userId == null ? null : (User) User.findById(userId); + User currentUser = user(); + List events; + List today; + if(user == null){ + events = Event.findAll(); //TODO: change to public and friends after visibility gets sorted + today = new ArrayList(); + } + else{ + events = user.myUpcomingEvents(); + today = user.todayEvents(); + } + render(user, currentUser, events, today); + } + + public static void upcoming(Long userId) { + User user = userId == null ? user() : (User) User.findById(userId); + List events; + List today; + if(userId == null){ + events = Event.find("SELECT r FROM Event r where r.endDate >= ? order by r.startDate", new Date()).fetch(); + today = new ArrayList(); + } + else { + events = user.myUpcomingEvents(); + today = user.todayEvents(); + } + render(user, events, today); + } + + public static void past(Long userId) { + User user = userId == null ? user() : (User) User.findById(userId); + List events; + List today; + if(userId == null){ + events = Event.find("SELECT r FROM Event r where r.endDate < ? order by r.startDate", new Date()).fetch(); + today = new ArrayList(); + } + else { + events = user.myPastEvents(); + today = new ArrayList(); + } + render(user, events, today); + } + + public static void declinedEvents(Long userId){ + User user = userId == null ? user() : (User) User.findById(userId); + List events; + List today; + if(userId == null){ + events = new ArrayList(); + today = new ArrayList(); + } + else { + events = user.myDeclinedEvents(); + today = user.declinedTodayEvents(); + } + render(user, events, today); + } + + public static void addEvent() { + render(); + } + + public static void addEventInvite(Long eventId, Long guestId) { + User guest = User.findById(guestId); + Event event = Event.findById(eventId); + event.inviteMember(guest); + event.save(); + event(event.id); + } + + public static void deleteEvent(Long eventId) { + Event event = Event.findById(eventId); + if(event == null) + notFound("Event does not exist"); + User user = user(); + if(!event.owner.equals(user)) + forbidden(); + event.delete(); + events(user.id); + } + + public static void event_create(Event curEvent, String startMonth, String startDay, String startTime, String endMonth, String endDay, String endTime) { + if (params.get("submit") != null) { + User currentUser = user(); + validation.required(curEvent.name).message("Event name is required"); + validation.required(curEvent.script).message("Event description is required"); + validation.required(curEvent.location).message("Event location is required"); + validation.isTrue(!startMonth.equals("-1")).message("Event start month is required"); + validation.isTrue(!startDay.equals("-1")).message("Event start day is required"); + validation.isTrue(!startTime.equals("-1")).message("Event start time is required"); + if (validation.hasErrors()) { + Event thisEvent = curEvent; + renderTemplate("Events/addEvent.html", thisEvent); + } + else { + Event event = curEvent; + event.owner = currentUser; + event.name = curEvent.name; + event.script = curEvent.script; + event.location = curEvent.location; + event.startDate = setDate(startTime, startMonth, startDay); + if (!endMonth.equals("-1") && !endDay.equals("-1") + && !endTime.equals("-1")) { + event.endDate = setDate(endTime, endMonth, endDay); + event.givenEndDate = true; + } + + if (curEvent.privilege.equals("open")) { + event.open = true; + } else if (curEvent.privilege.equals("friends")) { + event.friends = true; + } else if (curEvent.privilege.equals("inviteOnly")) { + event.inviteOnly = true; + } + event.invited = new HashSet(); + event.invited.add(currentUser); + event.maybe = new HashSet(); + event.awaitreply = new HashSet(); + event.members = new HashSet(); + event.declined = new HashSet(); + event.members.add(currentUser); + event.save(); + event(event.id); + } + } + else if(params.get("cancel") != null){ + events(user().id); + } + } + + public static String convertDateToString(Date myDate){ + DateFormat df = new SimpleDateFormat("MMMM d 'at' HH:mm a"); + return df.format(myDate); + } + + public static String convertDateTime(Date myDate){ + DateFormat df = new SimpleDateFormat("HH:mm a"); + return df.format(myDate); + } + + public static Date setDate(String time, String month, String day){ + int minutes = 0; + int hours = 0; + if(time.length() == 4){ + minutes = Integer.parseInt(time.substring(2,4)); + hours = Integer.parseInt(time.substring(0,2)); + } + else{ + hours = Integer.parseInt(time); + } + // Using Calendar because date manipulation with Date is deprecated. + Calendar cal = Calendar.getInstance(); + cal.set(cal.get(Calendar.YEAR), Integer.parseInt(month), Integer.parseInt(day), hours, minutes); + return cal.getTime(); + } + + public static void newEventPost(Long eventId, Long userId, String post_content){ + new Post((Event)Event.findById(eventId), (User)User.findById(userId), post_content).save(); + event(eventId); + } + + public static void leaveEvent(Long eventId, Long userId){ + User guest = User.findById(userId); + Event event = Event.findById(eventId); + event.removeMember(guest); + event.save(); + events(guest.id); + } + + public static void joinEvent(Long eventId, Long userId){ + User guest = User.findById(userId); + Event event = Event.findById(eventId); + event.addMember(guest); + event.save(); + event(event.id); + } + + public static void maybeEvent(Long eventId, Long userId){ + User guest = User.findById(userId); + Event event = Event.findById(eventId); + event.addMaybe(guest); + event.save(); + event(event.id); + } +} \ No newline at end of file diff --git a/test/app/controllers/FThreads.java b/test/app/controllers/FThreads.java new file mode 100644 index 0000000..b0a66f9 --- /dev/null +++ b/test/app/controllers/FThreads.java @@ -0,0 +1,41 @@ +package controllers; + +import play.*; +import play.mvc.*; +import play.data.validation.*; +import play.libs.*; +import play.cache.*; +import models.*; + +import java.util.*; + +import javax.persistence.*; + +public class FThreads extends OBController +{ + + @OneToMany(mappedBy = "fthread", cascade = CascadeType.ALL) + public List allComments; + + public static void listSingle(Long threadId) + { + FThread thread = FThread.findById(threadId); + User _user = Application.user(); + render(thread, _user); + } + + public static void newThread(Long categoryId, String title, String content) + { + Category c = Category.findById(categoryId); + FThread newThread = new FThread(c, title, Application.user(), + new Date(), content); + newThread.save(); + renderJSON(newThread.id); + } + + public static void deleteThread(Long threadId) + { + FThread t = FThread.findById(threadId); + t.delete(); + } +} diff --git a/test/app/controllers/GroupSearch.java b/test/app/controllers/GroupSearch.java new file mode 100644 index 0000000..881b5f9 --- /dev/null +++ b/test/app/controllers/GroupSearch.java @@ -0,0 +1,57 @@ +package controllers; + +import java.util.List; + +import org.hibernate.Hibernate; + +import play.db.Model; +import play.db.jpa.Transactional; +import play.exceptions.TemplateNotFoundException; +import play.modules.elasticsearch.search.SearchResults; +import play.mvc.Before; +import controllers.*; +import controllers.elasticsearch.ElasticSearchController; +import controllers.elasticsearch.ElasticSearchController.ObjectType; +import models.*; + +@ElasticSearchController.For(Group.class) +public class GroupSearch extends OBController { + + /** + * Index. + */ + public static void index() { + if (getControllerClass() == ElasticSearchController.class) { + forbidden(); + } + render("GroupSearch/index.html"); + } + + /** + * Search. + * + * @param page the page + * @param search the search + * @param searchFields the search fields + * @param orderBy the order by + * @param order the order + */ + public static void search(int page, String search, String searchFields, String orderBy, String order) { + ObjectType type = ObjectType.get(getControllerClass()); + notFoundIfNull(type); + if (page < 1) { + page = 1; + } + SearchResults results = type.findPage(page, search, searchFields, orderBy, order, (String) request.args.get("where")); + List objects = results.objects; + Long count = results.totalCount; + Long totalCount = type.count(null, null, (String) request.args.get("where")); + try { + render(type, objects, count, totalCount, page, orderBy, order); + } catch (TemplateNotFoundException e) { + render("GroupSearch/search.html", type, objects, count, totalCount, page, orderBy, order); + } + } + +} + diff --git a/test/app/controllers/Groups.java b/test/app/controllers/Groups.java new file mode 100644 index 0000000..b1597ad --- /dev/null +++ b/test/app/controllers/Groups.java @@ -0,0 +1,41 @@ +/** + * + */ +package controllers; + +import java.util.Date; + +import models.Group; +import models.Post; +import models.User; +import models.TimelineModel; +import java.util.Vector; +import models.User; + +/** + * @author kschlosser + * + */ +public class Groups extends OBController { + + public static void group(Long id){ + Group group= id==null ? null : (Group) Group.findById(id); + User _user = user(); + User _currentUser = user(); + render(group,_user,_currentUser); + } + + public static void newGroupPost(Long groupId, Long userId, String post_content){ + //Post to group + Post p = new Post((Group)Group.findById(groupId), (User)User.findById(userId), post_content).save(); + + User user = (User)User.findById(userId); + Group group = (Group)Group.findById(groupId); + //Add TimelineEvent to Timeline + if (user.timeline != null) + user.timeline.addEvent(user.id, group, TimelineModel.Action.CREATE, new Vector(), user.first_name + " " + user.last_name + " posted in " + group.groupName); + + group(groupId); + } + +} diff --git a/test/app/controllers/Likeables.java b/test/app/controllers/Likeables.java new file mode 100644 index 0000000..84800bc --- /dev/null +++ b/test/app/controllers/Likeables.java @@ -0,0 +1,37 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.db.jpa.*; +import play.mvc.*; +import models.*; + + +public class Likeables extends OBController { + public static void likes (Long likeableId) { + User user = user(); + Likeable thing = Likeable.findById(likeableId); + if(thing == null) + notFound(); + render(user, thing); + } + + public static void like (Long likeableId) { + Likeable thing = Likeable.findById(likeableId); + if(thing == null) + notFound(); + if(thing.addLike(user())) + ok(); + notModified(); + } + + public static void unLike (Long likeableId) { + Likeable thing = Likeable.findById(likeableId); + if(thing == null) + notFound(); + if(thing.removeLike(user())) + ok(); + notModified(); + } +} \ No newline at end of file diff --git a/test/app/controllers/Links.java b/test/app/controllers/Links.java new file mode 100644 index 0000000..0df6053 --- /dev/null +++ b/test/app/controllers/Links.java @@ -0,0 +1,14 @@ +package controllers; + +import java.util.*; +import play.db.jpa.*; +import models.*; + +public class Links extends OBController { + + public static void addLink(String url, String content){ + Post newPost = new Link(OBController.user(), content, url); + newPost.save(); + } + +} diff --git a/test/app/controllers/Messages.java b/test/app/controllers/Messages.java new file mode 100644 index 0000000..40789a3 --- /dev/null +++ b/test/app/controllers/Messages.java @@ -0,0 +1,53 @@ +package controllers; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +import controllers.Secure; + +import play.*; +import play.data.validation.Required; +import play.mvc.*; +import controllers.Secure; +import models.*; + +public class Messages extends OBController { + + public static void inbox() { + User user = user(); + render(user); + } + + public static void message(Long messageId) { + Message item = Message.findById(messageId); + if(item == null) { + notFound("That message does not exist."); + } + User user = user(); + render(user, item); + } + + public static void createMessage() { + User user = user(); + render(user); + } + + public static void sendMessage(@Required(message="Recipient is required") String recipientName, String content) { + User author = user(); + User recipient = User.find("byName", recipientName).first(); + validation.isTrue(recipient != null).message("Invalid Recipient"); + if(validation.hasErrors()){ + renderTemplate("Messages/createMessage.html", author); + } + else{ + Message m = new Message(author, recipient, content); + m.save(); + inbox(); + } + } + + + + +} diff --git a/test/app/controllers/Notes.java b/test/app/controllers/Notes.java new file mode 100644 index 0000000..9061fe6 --- /dev/null +++ b/test/app/controllers/Notes.java @@ -0,0 +1,29 @@ +package controllers; + +import models.Note; +import models.User; +import play.mvc.*; + +/* + * Author: Andy Eskridge + * email: andy.eskridge@gmail.com + */ + +public class Notes extends OBController { + + public static void viewNotes() { + User user = user(); + render(user); + } + + public static void newNote() { + User user = user(); + render(user); + } + + public static void saveNote(String title, String content) { + Note n = new Note(user(), title, content); + n.save(); + viewNotes(); + } +} diff --git a/test/app/controllers/OBController.java b/test/app/controllers/OBController.java new file mode 100644 index 0000000..36504bd --- /dev/null +++ b/test/app/controllers/OBController.java @@ -0,0 +1,31 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.mvc.*; +//import controllers.Secure; +import models.*; + +@With(OBSecure.class) +public abstract class OBController extends Controller { + + @Before + static void setConnectedUser() { + if (Security.isConnected() || request.user != null) { + renderArgs.put("currentUser", user()); + } + } + + @Before + static void addDefaults() { + } + + public static User user() { + if (request.user != null) { + return User.connect(request.user, request.password); + } + assert Secure.Security.connected() != null; + return User.getUser(Secure.Security.connected()); + } +} diff --git a/test/app/controllers/OBSecure.java b/test/app/controllers/OBSecure.java new file mode 100644 index 0000000..9201472 --- /dev/null +++ b/test/app/controllers/OBSecure.java @@ -0,0 +1,14 @@ +package controllers; + +import play.mvc.*; +import models.*; + +public class OBSecure extends Secure { + @Before(unless={"login", "authenticate", "logout"}) + static void checkAccess() throws Throwable { + if (request.user != null) + if (User.connect(request.user, request.password) != null) + session.put("username", request.user); + Secure.checkAccess(); + } +} \ No newline at end of file diff --git a/test/app/controllers/Pages.java b/test/app/controllers/Pages.java new file mode 100644 index 0000000..b3f541e --- /dev/null +++ b/test/app/controllers/Pages.java @@ -0,0 +1,134 @@ +package controllers; + +import java.awt.image.BufferedImage; +import java.util.*; +import javax.imageio.ImageIO; +import java.io.*; +import play.*; +import play.data.validation.Error; +import play.libs.*; +import play.mvc.*; +import play.db.jpa.*; +import models.*; +import java.security.*; +import java.net.*; +import java.awt.image.*; +import play.utils.HTML; + +@With(Secure.class) +public class Pages extends OBController { + + public static final String IMAGE_TYPE = "^image/(gif|jpeg|pjpeg|png)$"; + public static final int MAX_FILE_SIZE = 2 * 1024 * 1024; /* Size in bytes. */ + + public static void newPage(){ + User user = user(); + render(user); + } + + public static void pageSave(String title, String info){ + User user = user(); + User currentUser = user(); + Page page = new Page(user, title, info).save(); + display(page.id); + } + + + public static void pageUpdate(Long id, String info){ + Page page = Page.findById(id); + page.info = info; + page.save(); + User _user = user(); + display(id); + } + + public static void myPages(){ + User _user = user(); + List myPages = UserPage.find("select u from UserPage u where u.fan = ?", _user).fetch(); + List pages = Page.find("select p from Page p where p.admin = ?",_user).fetch(); + if(myPages == null){renderText("null");} + render(myPages, _user, pages); + } + + public static void display(Long id){ + User _user = user(); + User _currentUser = user(); + Page page = Page.findById(id); + boolean fan = isFan(id); + List myPages = UserPage.find("select u from UserPage u where u.fan = ?", _user).fetch(); + List photos = page.photos; + render("Pages/myPage.html", page, fan, _user, _currentUser, photos); + } + + public static void pages(){ + User user = user(); + List allPages = Page.findAll(); + render(allPages,user); + } + + public static void deletePage(Long id){ + User user = user(); + Page page = Page.findById(id); + UserPage link = UserPage.find("select u from UserPage u where u.page = ?", page).first(); + link.delete(); + page.delete(); + render(user); + } + + public static void unfan(String pid){ + Page page = Page.findById(Long.parseLong(HTML.htmlEscape(pid))); + UserPage u = UserPage.find("select u from UserPage u where u.page = ?", page).first(); + u.delete(); + Map m = new HashMap(); + m.put("fan",false); + renderJSON(m); + } + + public static void fan(String pid){ + User user = user(); + Page page = Page.findById(Long.parseLong(HTML.htmlEscape(pid))); + new UserPage(user, page).save(); + Map m = new HashMap(); + m.put("fan",true); + renderJSON(m); + } + + public static boolean isFan(Long id){ + User user = user(); + UserPage u = UserPage.find("select u from UserPage u where u.page.id = ? and u.fan = ?", id, user).first(); + if(u == null){return false;} + else{return true;} + } + + public static void addPhoto(Long id, File image) throws FileNotFoundException, + IOException { + Page page = Page.findById(id); + validation.keep(); /* Remember any errors after redirect. */ + + if (image == null || + !MimeTypes.getContentType(image.getName()).matches(IMAGE_TYPE)) { + validation.addError("image", + "validation.image.type"); + redirect("/users/" + user().id + "/photos"); + } + Photo photo = new Photo(user(), image,""); + validation.max(photo.image.length(), MAX_FILE_SIZE); + + if (!validation.hasErrors()) { + photo.save(); + page.photos.add(photo); + if(page.photos.size() == 1){ + page.profilePhoto = photo.id; + } + page.save(); + } + display(page.id); + } + + public static void setProfilePic(Long pid, Long photoid){ + Page p = Page.findById(pid); + p.profilePhoto = photoid; + p.save(); + display(pid); + } +} diff --git a/test/app/controllers/Photos.java b/test/app/controllers/Photos.java new file mode 100644 index 0000000..5c4837c --- /dev/null +++ b/test/app/controllers/Photos.java @@ -0,0 +1,268 @@ +package controllers; + +import java.awt.image.BufferedImage; +import java.util.*; +import javax.imageio.ImageIO; +import java.io.*; +import play.*; +import play.i18n.Messages; +import play.data.validation.Error; +import play.libs.*; +import play.mvc.*; +import play.db.jpa.*; +import models.*; + +import java.security.*; +import java.net.*; +import java.awt.image.*; + +public class Photos extends OBController { + + /* All possible image mime types in a single regex. */ + public static final String IMAGE_TYPE = "^image/(gif|jpeg|pjpeg|png)$"; + public static final int MAX_FILE_SIZE = 2 * 1024 * 1024; /* Size in bytes. */ + + public static void photos(Long ownerId) { + List photos; + if (ownerId == null) { + photos = Photo.find("byOwner", user()).fetch(); + } + else { + User user = User.findById(ownerId); + photos = Photo.find("byOwner", user).fetch(); + } + render(photos); + } + + public static void getPhoto(Long photoId) { + Photo photo = Photo.findById(photoId); + if (photo == null || !photo.visible(user())) { + notFound(Messages.get("photo.notFound")); + } + else { + response.setContentTypeIfNotSet(photo.image.type()); + renderBinary(photo.image.get()); + } + } + + /** + * Convert a given File to a Photo model.Used in Bootstrap.java + * + * @param image the file to convert. + * @return the newly created Photo model. + * @throws FileNotFoundException + */ + public static Photo initFileToPhoto(String path, String caption) + throws IOException, + FileNotFoundException { + File image = new File(path); + User user = User.find("username = ?", "default").first();//set owner as default owner + Photo photo = new Photo(user, image, caption); + /* Make all initial photos world-visible. */ + photo.visibility = Likeable.Visibility.PUBLIC; + photo.save(); + return photo; + } + + public static void addPhoto(File image) throws FileNotFoundException, + IOException { + validation.keep(); /* Remember any errors after redirect. */ + + if (image == null || + !MimeTypes.getContentType(image.getName()).matches(IMAGE_TYPE)) { + validation.addError("image", + "validation.image.type"); + redirect("/users/" + user().id + "/photos"); + } + + Photo photo = new Photo(user(), image); + validation.max(photo.image.length(), MAX_FILE_SIZE); + + if (!validation.hasErrors()) { + photo.save(); + + //Add a TimelineEvent to the Timeline, if the user has one + if (photo.owner.timeline != null) + photo.owner.timeline.addEvent(photo.owner.id, photo, TimelineModel.Action.CREATE, new Vector(), photo.owner.first_name + " " + photo.owner.last_name + " uploaded a picture "); + } + + redirect("/users/" + photo.owner.id + "/photos"); + } + + public static void removePhoto(Long photoId) { + Photo photo = Photo.findById(photoId); + if (photo == null) { + notFound(Messages.get("photo.notFound")); + } + if (!photo.owner.equals(user())) { + forbidden(); + } + User user = user(); + //deleting your profile photo results in going back to the default profile photo + if(user.profile.profilePhoto.equals(photo)) + { + User defaultUser = User.find("username= ?", "default").first(); + user.profile.profilePhoto = Photo.find("owner=? AND caption=?",defaultUser, "Default Profile Photo").first(); + user.profile.save(); + } + photo.delete(); + redirect("/users/" + photo.owner.id + "/photos"); + } + + + public static void setProfilePhotoPage() { + User user = user(); + List photos = Photo.find("byOwner", user).fetch(); + render(user,photos); + } + + + public static void changeBGImage() { + User user = user(); + photos(user.id); + } + + public static void setProfilePhoto(Long photoId) { + User user = user(); + + Photo photo = Photo.findById(photoId); + if (photo == null || !photo.visible(user)) { + notFound(Messages.get("photo.notFound")); + } + if (!photo.owner.equals(user())) { + forbidden(); + } + + user.profile.profilePhoto = photo; + user.profile.save(); + setProfilePhotoPage();//render page + } + + /** + * addProfilePhoto + * + * just does the adding of the photo and then uses setProfilePhoto to set the profilePhoto + * @param image + * @throws FileNotFoundException + * @throws IOException + */ + public static void addProfilePhoto(File image) throws FileNotFoundException, IOException { + if(image != null) { + try { + Photo photo = new Photo(user(), image); + validation.match(photo.image.type(), IMAGE_TYPE); + validation.max(photo.image.length(), MAX_FILE_SIZE); + + if (validation.hasErrors()) { + validation.keep(); /* Remember errors after redirect. */} + else { + photo.save(); + User user = user(); + user.profile.profilePhoto = photo; + user.profile.save(); + } + } catch(FileNotFoundException f) { + setProfilePhotoPage();//for if try to put in null file + } + } + + setProfilePhotoPage();//for if try to put in null file + } + + /** + * set gravatar to the profile photo + */ + + public static void setGravatar(String gravatarEmail) throws FileNotFoundException, IOException { + //first takes the user's email and makes it into the correct hex string + User u = user(); + String hash = md5Hex((gravatarEmail.trim()).toLowerCase()); + String urlPath = "http://www.gravatar.com/avatar/"+hash+".jpg"+ + "?" +//parameters + "size=120&d=mm"; + URL url = new URL(urlPath); + BufferedImage image = ImageIO.read(url); + if(u.profile.gravatarPhoto == null) { // don't yet have a gravatarPhoto + try { + File gravatar = new File(hash+".jpg"); + ImageIO.write(image, "jpg",gravatar); + + if(gravatar != null) { + Photo photo = new Photo(user(), gravatar); + validation.match(photo.image.type(), IMAGE_TYPE); + validation.max(photo.image.length(), MAX_FILE_SIZE); + + if (validation.hasErrors()) { + validation.keep(); /* Remember errors after redirect. */} + else { + photo.save(); + User user = user(); + user.profile.profilePhoto = photo; + + //set gravatarPhoto id + u.profile.gravatarPhoto = photo; + user.profile.save(); + } + gravatar.delete(); + } + } catch(Exception f) { + redirect("https://en.gravatar.com/site/signup/"); + } + } + else { // have already added the gravatar picture, so we need to displace pic. + Photo oldPhoto = Photo.findById(u.profile.gravatarPhoto.id); + try{ + File gravatar = new File(hash+".jpg"); + ImageIO.write(image, "jpg",gravatar); + + if(gravatar != null){ + oldPhoto.updateImage(gravatar); + validation.match(oldPhoto.image.type(), IMAGE_TYPE); + validation.max(oldPhoto.image.length(), MAX_FILE_SIZE); + + if (validation.hasErrors()) { + validation.keep(); /* Remember errors after redirect. */} + else { + oldPhoto.save(); + User user = user(); + user.profile.profilePhoto = oldPhoto; + + //set gravatarPhoto id + u.profile.gravatarPhoto = oldPhoto; + user.profile.save(); + } + + } + + gravatar.delete();//delete file. We don't need it + } + catch(Exception f) { + redirect("https://en.gravatar.com/site/signup/"); + } + } + + //if reach here have successfully changed the gravatar so we reset the email + u.profile.gravatarEmail = gravatarEmail; + u.profile.save(); + + setProfilePhotoPage();//render page + } + + /** + * helper method for gravatar + * makes String into md5hex + * @param message + * @return + */ + private static String md5Hex (String message) { + try { + MessageDigest md = + MessageDigest.getInstance("MD5"); + return Codec.byteToHexString(md.digest(message.getBytes("CP1252"))); + } catch (NoSuchAlgorithmException e) { + } catch (UnsupportedEncodingException e) { + } + return null; + } +} + diff --git a/test/app/controllers/Posts.java b/test/app/controllers/Posts.java new file mode 100644 index 0000000..6b08c78 --- /dev/null +++ b/test/app/controllers/Posts.java @@ -0,0 +1,81 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.mvc.*; +import controllers.Secure; +import models.*; + +public class Posts extends OBController { + + public static void posts(Long userId) { + List posts; + User user; + if(userId == null) { + user = user(); + posts = Post.findVisible(user); + } + else { + user = User.findById(userId); + if (user == null) + notFound(); + posts = user.posts; + } + render(user, posts); + } + + public static void post(Long postId) { + User user = user(); + Post post = Post.findById(postId); + if(post != null) + render(post, user); + else + notFound("That post does not exist."); + } + + public static void deletePost(Long postId) { + User user = user(); + Post p = Post.findById(postId); + if (p == null) + notFound(); + if (!p.owner.equals(user)) + forbidden(); + p.delete(); + ok(); + } + + public static void makeNewPost(String content) { + if (content == null) + error("content can't be null"); + User user = user(); + final Post post = new Post(user, user, content).save(); + render(user, post); + } + + public static void makeNewPagePost(String postContent, String pid) { + Page page = Page.findById(Long.parseLong(pid)); + final Post p = new Post(page, user(), postContent).save(); + Map m = new HashMap(); + m.put("item", p); + m.put("user", user()); + m.put("currentUser", user()); + renderTemplate(m); + } + + public static void makeNewGroupPost(String postContent, String gid) { + Group group = Group.findById(Long.parseLong(gid)); + final Post p = new Post(group, user(), postContent).save(); + Map m = new HashMap(); + m.put("item", p); + m.put("user", user()); + m.put("currentUser", user()); + renderTemplate(m); + } + + public static void poke(Long userId) { + String poked = new String(user() + " has poked " + (User)User.findById(userId) + "!"); + new Post(user(), user(), poked).save(); + posts(userId); + } +} diff --git a/test/app/controllers/Profiles.java b/test/app/controllers/Profiles.java new file mode 100644 index 0000000..8f5fffc --- /dev/null +++ b/test/app/controllers/Profiles.java @@ -0,0 +1,166 @@ +package controllers; + +import java.text.*; +import java.util.*; + +import play.*; +import play.mvc.*; +import controllers.Secure; +import models.*; +import models.Profile.Relationship; + +import models.Enrollment; +import models.Language; +import models.Location; +import models.Profile; +import models.User; +import models.UserLanguage; + +import org.apache.ivy.util.cli.ParseException; + +import play.data.validation.Error; +import play.data.validation.Match; + +public class Profiles extends OBController { + + public static void updateBio(String bio){ + User user = user(); + Profile profile = Profile.find("owner = ?", user).first(); + + if(!bio.equals("Write About Yourself")) + profile.bio = bio; + else + profile.bio = ""; + + profile.save(); + renderTemplate("Users/profile.html", profile); + } + + public static void updateInformation(String birthday, String relationshipStatus, String gender, String interestedIn, + String anniversary, String language, String religion, String political){ + User user = user(); + Profile profile = Profile.find("owner = ?", user).first(); + profile.religion = religion; + profile.relationshipStatus = Profile.Relationship.fromString(relationshipStatus); + DateFormat birthday_formatting = new SimpleDateFormat("MM/dd/yyyy"); + if(birthday != null){ + try{ + profile.birthday = (Date) birthday_formatting.parse(birthday); + } catch (java.text.ParseException e) { + Logger.error("Birthday should be in format: MM/dd/yyyy", e); + validation.match(birthday, ("\\^\\(0\\[1-9\\]\\|1\\[012\\]\\)\\[-/.\\]\\(0\\[1-9\\]\\|\\[12\\]\\[0-9\\]\\|3\\[01\\]\\)\\[-/.\\]\\(19\\|20\\)\\d\\d\\$")); + } + } + + profile.gender = gender; + profile.interestedIn = interestedIn; + DateFormat anniversary_formatting = new SimpleDateFormat("MM/dd/yyyy"); + if(anniversary != null){ + try { + profile.anniversary = (Date) anniversary_formatting.parse(anniversary); + } catch (java.text.ParseException e) { + Logger.error("Anniversary should be in format: MM/dd/yyyy", e); + validation.match(anniversary, ("\\^\\(0\\[1-9\\]\\|1\\[012\\]\\)\\[-/.\\]\\(0\\[1-9\\]\\|\\[12\\]\\[0-9\\]\\|3\\[01\\]\\)\\[-/.\\]\\(19\\|20\\)\\d\\d\\$")); + } + + } + + Language lang = Language.find("name = ?", language).first(); + UserLanguage userlang = new UserLanguage(profile, lang); + if (lang != null){ + userlang.save(); + profile.languages.add(userlang); + } + + profile.political = political; + profile.save(); + renderTemplate("Users/profile.html", profile); + } + + public static void updateContactInfo(String phone, String address){ + User user = user(); + Profile profile = Profile.find("owner = ?", user).first(); + String previousPhone = profile.phone; + if(!phone.equals("Add A Phone Number")){ + profile.phone = phone; + } + else + profile.phone = ""; + validation.phone(profile.phone); + if(validation.hasErrors()) { + profile.phone = previousPhone; + } + + if(!address.equals("Add Current Address")) + profile.address = address; + else + profile.address = ""; + + profile.save(); + renderTemplate("Users/profile.html", profile); + } + + public static void updateWorkEdu(String edu, String work){ + User user = user(); + Profile profile = user.profile; + + if(!edu.equals("Add A School")){ + String[] schools = edu.split(","); + for (String school : schools){ + if(!school.equals("Add A School")){ + Enrollment enrollment = Enrollment.find("byName", school).first(); + if (enrollment == null){ + enrollment = new Enrollment(school); + enrollment.student = profile; + enrollment.save(); + } + if(!profile.education.contains(enrollment)) + profile.education.add(enrollment); + } + } + } + else + profile.education = new ArrayList(); + + /* + Employment employment = new Employment(work); + employment.employee = profile; + employment.save(); + profile.work.add(employment); + */ + profile.save(); + renderTemplate("Users/profile.html", profile); + } + + public static void updateLiving(String hometown){ + User user = user(); + Profile profile = user.profile; + + if(!hometown.equals("Add Hometown")){ + Location loc = Location.find("location = ?", hometown).first(); + if(loc == null){ + loc = new Location(hometown); + loc.save(); + } + profile.hometown = loc; + } + else + profile.hometown = null; + + profile.save(); + renderTemplate("Users/profile.html", profile); + } + + public static void updateQuote(String quotation){ + User user = user(); + Profile profile = Profile.find("owner = ?", user).first(); + + if(!quotation.equals("Add a Favorite Quotation")) + profile.quotes = quotation; + else + profile.quotes = ""; + + profile.save(); + renderTemplate("Users/profile.html", profile); + } +} \ No newline at end of file diff --git a/test/app/controllers/Questions.java b/test/app/controllers/Questions.java new file mode 100644 index 0000000..b96a9b8 --- /dev/null +++ b/test/app/controllers/Questions.java @@ -0,0 +1,19 @@ +package controllers; + +import java.util.HashSet; +import java.util.Set; + +import models.Answer; +import models.Post; +import models.Question; + +public class Questions extends OBController{ + + public static void addQuestion(String question, String[] answers){ + Question q = new Question(user(), question); + q.save(); + for(String s : answers) + new Answer(q, s).save(); + redirect("/"); + } +} diff --git a/test/app/controllers/RSSFeeds.java b/test/app/controllers/RSSFeeds.java new file mode 100644 index 0000000..1664e1f --- /dev/null +++ b/test/app/controllers/RSSFeeds.java @@ -0,0 +1,46 @@ +package controllers; + +import org.hibernate.exception.ConstraintViolationException; + +import java.util.*; + +import org.w3c.dom.Document; + +import play.*; +import play.db.jpa.GenericModel.JPAQuery; +import play.libs.WS; +import play.mvc.*; +import play.utils.HTML; +import controllers.Secure; +import models.*; + +public class RSSFeeds extends OBController { + + public static void addFeed(String url) { + if(url != null && !url.trim().equals("")){ + User u = user(); + RSSFeed feed = new RSSFeed(u, url.trim()); + if (feed.is_valid) { + try { + feed.save(); + renderJSON("1"); + } catch (ConstraintViolationException e) { + } + } + } + renderJSON("0"); + } + public static void RSSfeeds(Long userId) { + User current = User.findById(userId); + if (current != null){ + List feeds = new ArrayList(); + + for(RSSFeed f : current.feeds) { + if (!f.is_valid) continue; + feeds.add(f); + } + render(feeds); + } + } +} + diff --git a/test/app/controllers/Security.java b/test/app/controllers/Security.java new file mode 100644 index 0000000..9c3833a --- /dev/null +++ b/test/app/controllers/Security.java @@ -0,0 +1,18 @@ +package controllers; + +import models.*; + +public class Security extends Secure.Security { + public static String connected() { + return Secure.Security.connected(); + } + + static boolean authenticate(String username, String password) { + return User.connect(username, password) != null; + } + + // deprecated + static boolean authentify(String username, String password) { + return User.connect(username, password) != null; + } +} diff --git a/test/app/controllers/Signup.java b/test/app/controllers/Signup.java new file mode 100644 index 0000000..bf4ab3e --- /dev/null +++ b/test/app/controllers/Signup.java @@ -0,0 +1,159 @@ +package controllers; + +import java.io.File; +import java.util.*; + +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; + +import controllers.Secure; +import models.TempUser; +import models.User; +import play.Play; +import play.cache.Cache; +import play.data.validation.Error; +import play.data.validation.Required; +import play.libs.Codec; +import play.libs.IO; +import play.libs.Images; +import play.libs.Mail; +import play.mvc.*; +//import controllers.Secure; + +public class Signup extends Controller { + + public static void signup() { + String randomID = Codec.UUID(); + render(randomID); + } + + public static void captcha(String id) { + Images.Captcha captcha = Images.captcha(); + String code = captcha.getText("#000"); + Cache.set(id, code, "10mn"); + renderBinary(captcha); + } + + public static void get_new_captcha() { + String randomID = Codec.UUID(); + renderText(randomID); + } + + public static void signup_user(String firstName, String lastName, String username, String email, String email2, String password, String password2, + @Required(message="Please type the code") String code, String randomID) { + validation.email(email).message("Please use a valid email address"); + validation.isTrue(email.trim().length() >= 1).message("Please use a valid email address"); + validation.equals(email, email2).message("Email addresses do match" + email + email2); + validation.isTrue(checkUniqueEmail(email)).message("An account is already attached to this email address. Did you forget your password?"); + validation.isTrue(firstName.trim().length() >= 1).message("Please enter a first name"); + validation.isTrue(lastName.trim().length() >= 1).message("Please enter a last name"); + username = username.trim(); + validation.isTrue(checkUniqueUsername(username)).message("This username is in use"); + validation.isTrue(username.trim().length() >= 4).message("Username must be at least 4 characters"); + validation.isTrue(password.length() >= 6).message("Password must be at least 6 characters"); + validation.match(password, ".*[A-Z]+.*").message("Password must contain an uppercase letter"); + validation.match(password, ".*[a-z]+.*").message("Password must contain a lowercase letter"); + validation.match(password, "(.*\\W+.*)|(.*[0-9]+.*)").message("Password must contain a non-letter character"); + validation.equals(password, password2).message("Passwords do match"); + if(!Play.id.equals("test")) { + validation.equals(code, Cache.get(randomID)).message("Invalid code. Please type it again"); + } + if (validation.hasErrors()) { + String errors =""; + for(Error error : validation.errors()) { + errors += error.message() + "
    "; + } + renderText(errors); + } + else { + try { + String confirmID = Codec.UUID(); + new TempUser(email, password, username, firstName, lastName, confirmID).save(); + sendConfirmationEmail(email, confirmID); + } catch (EmailException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + flash.put("success", "Registration almost complete! Just verify your e-mail address, and you will be able to log in"); + flash.keep(); + renderText(""); + } + } + + /** Sends an email to confirm valid emails and complete registration for a user. + * + * @param emailTo the users email + * @param confirmID the confirmation id + * @throws EmailException thrown from the SimpleEmail class + */ + private static void sendConfirmationEmail(String emailTo, String confirmID) throws EmailException { + HashMap map = new HashMap(); + map.put("id", confirmID); + String url = Router.reverse("Signup.confirm", map).url; + url = Play.configuration.getProperty("application.baseUrl") + url; + String password = IO.readContentAsString(new File("conf/passwd.pwd")).trim(); + Play.configuration.setProperty("mail.smtp.pass", password); + SimpleEmail email = new SimpleEmail(); + email.setFrom("registration@openbook.com"); + email.addTo(emailTo); + email.setSubject("Welcome to OpenBook! Please confirm your e-mail"); + email.setMsg("Welcome to OpenBook! We are glad to have you onboard - but we need to confirm your email first. You can do so by going here: " + url); + Mail.send(email); + } + + /** Confirms the email for a given id and creates the user in the database. + * + * @param id the UUID assigned at registration time. + */ + public static void confirm(String id) { + TempUser user = TempUser.find("SELECT u FROM TempUser u WHERE u.UUID = ?", id).first(); + if(user == null) { + return; + } + if (user.verified == false) { + new User(user).save(); + } + flash.put("success", "E-mail verified and registration complete! Sign in below."); + flash.keep(); + try { + Secure.login(); + } catch (Throwable e) {}; + } + + public static void isValidUserName(String name) { + if (!checkUniqueUsername(name)) { + renderText("This username has been taken"); + } else if (name.length() < 4) { + renderText("The username must have at least 4 characters"); + } else { + renderText("Username available :)"); + } + } + + private static boolean checkUniqueUsername(String name) { + if (User.count("username = ?", name) > 0) { + return false; + } else { + return true; + } + } + + private static boolean checkUniqueEmail(String email) { + if (User.count("email = ?", email) > 0) { + return false; + } else { + return true; + } + } + + public static void isValidEmail(String email) { + if (validation.email(email).ok == false || email.trim().length() == 0) { + renderText("Please use a valid email address"); + } + else if (!checkUniqueEmail(email)) { + renderText("An account is already attached to this email address. Did you forget your password?"); + } else { + renderText(":)"); + } + } +} \ No newline at end of file diff --git a/test/app/controllers/Skins.java b/test/app/controllers/Skins.java new file mode 100644 index 0000000..1f7a9d8 --- /dev/null +++ b/test/app/controllers/Skins.java @@ -0,0 +1,201 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.mvc.*; +import controllers.Secure; +import models.*; +import controllers.Photos; + +@With(Secure.class) +public class Skins extends OBController { + public static List skins() { + List skinList = Skin.find("isPublic = ?", "true").fetch(); + return skinList; + } + + public static void sampleSkin(Long skinId) + { + User user = user(); + Skin skin; + if(skinId == null) + { + skin = Skin.find("skinName = ?","default_skin").first();//get default skin + } + else + { + skin = Skin.findById(skinId); + } + render(user,skin); + } + /** + * stylesheet() + * called by main.html + * renders the appropriate stylesheet skin for the current user + */ + public static void stylesheet() { + User user = user(); + Skin skin = user.profile.skin; + renderTemplate("/public/stylesheets/main.css",skin); + } + + /** + * renders change skin page + */ + public static void changeSkin(Long id) { + User user = id == null ? user() : (User) User.findById(id); + List skinList = skins(); + render(user, skinList); + } + + /** + * editMySkin + * renders edit skin page + * if we are editing the skin, then we need to create a new skin so we can only edit our own skin + */ + public static void editMySkin(Long id,String makeSkinOutput) { + User user = id == null ? user() : (User) User.findById(id); + render(user, makeSkinOutput); + } + + /** + * given helper method --tells whether or not the form has any input + * @param val String + * @return + */ + private static boolean given(String val) { + return val != null && val.length() > 0; + } + + /** + * edit_skin + * changes attributes of the skin + * If there are no changes to the attribute, the skin doesn't change. + * If there are changes, changes appropriately + * If there are bad changed, goes to default null. + */ + public static void editSkin(String key, String val) + { + User user = user(); + Skin currentUserSkin = user.profile.skin; + System.out.println("val: " + val); + if(!val.contains(";") && !val.contains(".")) + {//checks for SQL injection + if(user.profile.skin.userName != user.username){//each user gets a unique skin + Skin newSkin = new Skin(user.username,"mySkin");//make a skin for that user + newSkin.cloneSkin(currentUserSkin); + user.profile.skin = newSkin; + user.profile.save(); + } + + if(key != null){//null if theres no changes + + String[] keys = key.split(", ");//input is a list + String[] values = val.split(", "); + String keyUpdate = ""; + String valueUpdate = ""; + + //go through the attributes + for(int x = 0; x< keys.length; x++) + { + keyUpdate = keys[x]; + valueUpdate = values[x]; + + if(given(valueUpdate))//if the attribute has been filled, set parameter + { + user.profile.skin.setParam(keyUpdate,valueUpdate); + + } + } + } + + //save changes + user.profile.save(); + + + } + editMySkin(user.id,null);//rerender the page for current user (input null will find user(); + } + + /** + * changes Skin to template skin + * just sets our parameters be the same + * used so that can redirect later and won't change if skin name is not there + */ + public static void changeSkinToTemplate(String skinName) + { + //find skin + User user = user(); + Skin changeSkin = Skin.find("userName = ? AND skinName = ?", "default", skinName).first(); + if(changeSkin != null) + { + user.profile.skin = changeSkin; + user.profile.save(); + } + changeSkin(user.id);//rerender page + } + + public static void setBackgroundPhoto(Long photoid) + { + User user = user(); + Skin changeSkin = user.profile.skin; + if(user.profile.skin.userName != user.username){//each user gets a unique skin + Skin newSkin = new Skin(user.username,"mySkin");//make a skin for that user + newSkin.cloneSkin(changeSkin); + user.profile.skin = newSkin; + user.profile.save(); + changeSkin = user.profile.skin; + } + + SkinPair update = SkinPair.find("attachedSkin = ? AND name = ?", changeSkin, "bodyBGPhoto").first(); + if(update != null) + { + update.value = "/photos/" + photoid.toString(); + update.save(); + } + Photos.photos(user.id); + } + + public static Skin getSkin(String userName, String skinName) + { + return Skin.find("userName = ? AND skinName = ?",userName, skinName).first(); + } + + public static void makeSkin(String skinName) + { + User user = user(); + String makeSkinOutput = ""; + + if(!user.profile.skin.userName.equals(user.username)) + { + makeSkinOutput = "You cannot make a new Skin from a template."; + } + else + { + //security check + if(!skinName.contains(";") && !skinName.contains(".")) + { + //we want anyone to be able to use this skin, so it can't be allowed to change + Skin s2 = Skin.find("userName = ? AND skinName = ?", "default", skinName).first(); + if(s2!=null) + makeSkinOutput = ("Skin Name has already been used in the templates." + + " Please specify another skin name."); + else{ + Skin newSkin = new Skin("default",skinName);//make a template skin of that user + newSkin.cloneSkin(user.profile.skin); + newSkin.isPublic = "true"; + newSkin.save(); + //change the profile's skin + user.profile.skin = newSkin; + user.profile.save(); + makeSkinOutput = "SUCCESS!"; + } + + } + } + editMySkin(user.id,makeSkinOutput);//rerender the page for current user (input null will find user(); + + } + +} \ No newline at end of file diff --git a/test/app/controllers/Statuses.java b/test/app/controllers/Statuses.java new file mode 100644 index 0000000..6dd1e24 --- /dev/null +++ b/test/app/controllers/Statuses.java @@ -0,0 +1,31 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.mvc.*; +import controllers.Secure; +import models.*; +import play.data.validation.*; + +@With(Secure.class) +public class Statuses extends OBController { + + public static void show(Long id){ + Status status = Status.findById(id); + User author = User.findById(id); + render(status, author); + } + + public static void postStatus( + @Required(message="A message is required") String content) + { + + new Status(Application.user(), content).save(); + Application.news(Application.user().id); + } + + public List returnAll(){ + return Status.findAll(); + } +} diff --git a/test/app/controllers/Subscriptions.java b/test/app/controllers/Subscriptions.java new file mode 100644 index 0000000..0beeecf --- /dev/null +++ b/test/app/controllers/Subscriptions.java @@ -0,0 +1,21 @@ +package controllers; + +import java.util.*; + +import play.*; +import play.mvc.*; +import controllers.Secure; +import models.*; + +@With(Secure.class) +public class Subscriptions extends OBController { + + public static void addSubscription(Long id) { + + } + + public static void subscriptions(Long id) { + User user = id == null ? user() : (User) User.findById(id); + render(user); + } +} diff --git a/test/app/controllers/Thumbnails.java b/test/app/controllers/Thumbnails.java new file mode 100644 index 0000000..044077d --- /dev/null +++ b/test/app/controllers/Thumbnails.java @@ -0,0 +1,36 @@ +package controllers; + +import play.i18n.Messages; +import play.db.jpa.Blob; +import models.Photo; + +public class Thumbnails extends OBController { + + private static Photo getPhotoIfVisible(long photoId) { + Photo photo = Photo.findById(photoId); + if (photo == null || !photo.visible(user())) { + notFound(Messages.get("photo.notFound")); + } + return photo; + } + + private static void renderBlob(Blob thumbnail) { + response.setContentTypeIfNotSet(thumbnail.type()); + renderBinary(thumbnail.get()); + } + + public static void get120x120(Long photoId) { + Photo photo = getPhotoIfVisible(photoId); + renderBlob(photo.thumbnail120x120); + } + + public static void get50x50(Long photoId) { + Photo photo = getPhotoIfVisible(photoId); + renderBlob(photo.thumbnail50x50); + } + + public static void get30x30(Long photoId) { + Photo photo = getPhotoIfVisible(photoId); + renderBlob(photo.thumbnail30x30); + } +} diff --git a/test/app/controllers/Timeline.java b/test/app/controllers/Timeline.java new file mode 100644 index 0000000..f4a527d --- /dev/null +++ b/test/app/controllers/Timeline.java @@ -0,0 +1,21 @@ +package controllers; + +import java.util.*; + +import java.util.Date; +import models.TimelineModel; +import models.Post; +import models.User; + + +public class Timeline extends OBController { + + public static void Timeline(Long userId) { + User user = userId == null ? user() : (User) User.findById(userId); + User currentUser = user(); + render(currentUser, user); + } + +} + + diff --git a/test/app/controllers/UpcomingBirthdays.java b/test/app/controllers/UpcomingBirthdays.java new file mode 100644 index 0000000..e2a3c9a --- /dev/null +++ b/test/app/controllers/UpcomingBirthdays.java @@ -0,0 +1,60 @@ +package controllers; + +import java.util.*; + +import org.elasticsearch.index.query.QueryBuilders; + +import play.*; +import play.modules.elasticsearch.ElasticSearch; +import play.modules.elasticsearch.search.SearchResults; +import play.mvc.*; +import controllers.Secure; +import models.*; +import play.libs.Crypto; + + +public class UpcomingBirthdays extends OBController { + + public static void showUpcomingBirthdays(Long id) { + User current = User.findById(id); + if (current == null) + notFound(); + + Date today = new Date(); + int day = today.getDate(); + Date thisWeek = new Date(); + thisWeek.setDate(day + 8); + int thisYear = today.getYear()+1900; + + Date y = new Date(); + y.setDate(day); + y.setYear(-10); + + + List todayBday = new ArrayList(); + List thisWeekBday = new ArrayList(); + + + + for(User u : current.friends) { + Date friendBirthday = u.profile.birthday; + + if(friendBirthday == null) { //The user's friend did not set a birthday date field + u.profile.birthday = y; //for testing purposes + friendBirthday = y; //for testing purposes + //continue; //comment out for testing + } + friendBirthday.setYear(today.getYear()); + + if (friendBirthday.equals(today)) + todayBday.add(u); + else if(friendBirthday.before(thisWeek) && friendBirthday.after(today)) + thisWeekBday.add(u); + + + //y.setYear(1992); //for testing purposes + } + + render(thisWeekBday, todayBday, thisYear); + } +} \ No newline at end of file diff --git a/test/app/controllers/UserSearch.java b/test/app/controllers/UserSearch.java new file mode 100644 index 0000000..68c3ef1 --- /dev/null +++ b/test/app/controllers/UserSearch.java @@ -0,0 +1,59 @@ +package controllers; + +import java.util.List; + +import org.hibernate.Hibernate; + +import play.db.Model; +import play.db.jpa.Transactional; +import play.exceptions.TemplateNotFoundException; +import play.modules.elasticsearch.search.SearchResults; +import play.mvc.Before; +import controllers.*; +import controllers.elasticsearch.ElasticSearchController; +import controllers.elasticsearch.ElasticSearchController.ObjectType; +import models.*; + +@ElasticSearchController.For(User.class) +public class UserSearch extends OBController { + + /** + * Index. + */ + public static void index() { + if (getControllerClass() == ElasticSearchController.class) { + forbidden(); + } + render("UserSearch/index.html"); + } + + /** + * Search. + * + * @param page the page + * @param search the search + * @param searchFields the search fields + * @param orderBy the order by + * @param order the order + */ + public static void search(int page, String search, String searchFields, String orderBy, String order) { + ObjectType type = ObjectType.get(getControllerClass()); + notFoundIfNull(type); + if (page < 1) { + page = 1; + } + searchFields = "email, first_name, last_name, name"; + + SearchResults results = type.findPage(page, search, searchFields, orderBy, order, (String) request.args.get("where")); + List objects = results.objects; + Long count = results.totalCount; + Long totalCount = type.count(null, null, (String) request.args.get("where")); + try { + render(type, objects, count, totalCount, page, orderBy, order); + } catch (TemplateNotFoundException e) { + render("UserSearch/search.html", type, objects, count, totalCount, page, orderBy, order); + } + } + +} + diff --git a/test/app/controllers/Users.java b/test/app/controllers/Users.java new file mode 100644 index 0000000..70d7b64 --- /dev/null +++ b/test/app/controllers/Users.java @@ -0,0 +1,142 @@ +package controllers; + +import models.*; + +import java.util.*; + + +public class Users extends OBController { + + public static void users() { + List users = User.findAll(); + render(users); + } + + public static void user(Long userId) { + User user = userId == null ? user() : (User) User.findById(userId); + User currentUser = user(); + render(currentUser, user); + } + + public static void deleteUser(Long userId) { + User user = user(); + if (!user.equals(User.findById(userId))) + unauthorized(); + user.delete(); + try { + Secure.logout(); + } catch (Throwable t) { + System.out.println("freakout!"); + } + } + + public static void updateUser(String json) { + //TODO: parse json aout!"); + } + + public static void updateUser(Long userId, String json) { + renderText(userId.toString() + json); + //TODO: parse json and call Application.account_save + } + + public static List fullNames() { + List users = User.findAll(); + List names = new ArrayList(); + for(User u : users){ + names.add(u.name); + } + return names; + } + + public static void friends(Long userId) { + User user = User.findById(userId); + User currentUser = user(); + if (user == null) + notFound(); + if (!(user.isFriendsWith(currentUser) || user.equals(currentUser))) + unauthorized(); + Set friends = new HashSet(user.friends); + friends.remove(user); + render(currentUser, friends); + } + + public static void friendRequests(Long userId) { + User user = user(); + if (userId != null && userId != user.id) + unauthorized(); + render(user); + } + + public static void autocompleteNames(final String term) { + final List response = new ArrayList(); + for (String name : fullNames()) { + if (name.toLowerCase().startsWith(term.toLowerCase())) { + response.add(name); + } + if (response.size() == 10) { + break; + } + } + renderJSON(response); + } + + public static void profile(Long userId) { + User user = userId == null ? user() : (User)User.findById(userId); + if(user == null) + notFound(); + Profile profile = user.profile; + if(profile == null) + notFound(); + render(user, profile); + } + + /** Request to be friends with a given user + * + * @param userId the user to request friendship with + */ + + public static void requestFriends(Long userId) { + User user = user(); + User other = User.findById(userId); + if(other == null) + notFound(); + + // I know it's redundant, but it's helpful for testing purposes + if(user.equals(other)) { + user.friends.add(other); + user.save(); + renderText("friends"); + } + + // If the other person has already requested friendship with you + if (user.friendRequests.contains(other)) { + user.friendRequests.remove(other); + user.friends.add(other); + other.friends.add(user); + user.save(); + other.save(); + renderText("friends"); + } + other.friendRequests.add(user); + other.save(); + renderText("requested"); + } + + /** Attempt to end a relationship with a user + * + * @param userId the user to remove + */ + public static void removeFriends(Long userId) { + User user = user(); + User other = User.findById(userId); + if (other == null) + notFound(); + other.friends.remove(user); + user.friends.remove(other); + user.friendRequests.remove(other); + other.friendRequests.remove(user); + user.save(); + other.save(); + ok(); + } +} \ No newline at end of file diff --git a/test/app/models/Album.java b/test/app/models/Album.java new file mode 100644 index 0000000..fc2139e --- /dev/null +++ b/test/app/models/Album.java @@ -0,0 +1,79 @@ +/**Album + * purpose: Defines the + * + * created by: Chris. Cale + * + * email: collegeassignment@gmail.com + * + */ + +package models; + +import java.util.*; +import javax.persistence.*; +import play.db.jpa.*; +import play.data.validation.*; + +@Entity +public class Album extends Model{ + + +// @Id +// public Long albumId; + + @Required + public String title; + @Required + public Date dateCreated; + @Required + public Date lastDateModified; + + @ManyToOne + @Required + public User owner; + + @OneToMany//(mappedBy = "Album",cascade = CascadeType.ALL) + public List photos; + + + /**Default constructor + * + * @param albumName the name of the photo album is set to "untitled" + * @param albumId the automatically generated UIG for this album + * @param user the current user is set as the owner of this album + * @param dateCreated the date that the album was created + * @param lastDateModified the last date album was modified by the user + * + * @return an album that contains photos + */ + public Album(User owner){//default constructor + this.title = "untitled"; + //this.albumId = getId(); + this.owner = owner; + this.dateCreated = new Date(); + this.lastDateModified = new Date(); + this.photos = new ArrayList(); + } + + /**Non-default constructor + * + * @param albumName the name of the photo album to user String input + * @param albumId the automatically generated UIG for this album + * @param user the current user is set as the owner of this album + * @param dateCreated the date that the album was created + * @param lastDateModified the last date album was modified by the user + * + * @return an album that contains photos + */ + public Album(String albumName, User owner){ + this.title = albumName; + //this.albumId = getId(); + this.owner = owner; + this.dateCreated = new Date(); + this.lastDateModified = new Date(); + this.photos = new ArrayList(); + } + + + +}//end of class diff --git a/test/app/models/Answer.java b/test/app/models/Answer.java new file mode 100644 index 0000000..9bfa575 --- /dev/null +++ b/test/app/models/Answer.java @@ -0,0 +1,76 @@ +package models; + +import java.util.Set; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; + +import play.data.validation.Required; + +@Entity +public class Answer extends Model { + + public enum Visibility {PRIVATE, FRIENDS, PUBLIC}; + + @Required + public Visibility visibility; + + @Required + public String answer; + + @ManyToOne + public Question question; + + @Required + @JoinTable(name="answers_table") + @ManyToMany(cascade=CascadeType.PERSIST) + public Set usersWhoAnswered; + + public Answer(Question question, String answer){ + this.answer = answer; + this.question = question; + } + + public Answer addUserChoice(User user){ + for(Answer a : question.answers) + if(a.removeUserChoice(user)) + a.save(); + usersWhoAnswered.add(user); + user.userAnswers.add(this); + user.save(); + this.save(); + return this; + } + + public boolean removeUserChoice(User user){ + return usersWhoAnswered.remove(user); + } + + public boolean answeredBy(User user){ + return usersWhoAnswered.contains(user); + } + + public int numTimesAnswered(){ + return usersWhoAnswered.size(); + } + + public boolean visible(User user) { + User owner = User.findById(question.owner.id); + if(visibility == Visibility.PRIVATE) + return user.equals(owner); + if(visibility == Visibility.FRIENDS) + return user.equals(owner) || user.isFriendsWith(owner); + return true; + } + + // Return the percentage of times this was chosen vs all other answers for this question. + public int percentage(){ + if(question.totalUserAnswers() == 0) + return 0; + return (numTimesAnswered()*100)/question.totalUserAnswers(); + } + +} diff --git a/test/app/models/Category.java b/test/app/models/Category.java new file mode 100644 index 0000000..f3ab013 --- /dev/null +++ b/test/app/models/Category.java @@ -0,0 +1,27 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import play.db.jpa.*; + +@Entity +public class Category extends Model { + + public String name; + public String description; + public Likeable latest; + + @OneToMany(mappedBy="category", cascade=CascadeType.ALL) + public List threads; + + public Category(String name, String description) { + this.name = name; + this.description = description; + + } + + public FThread get_most_recent(){ + return FThread.find("category = ? order by postedAt desc", this).first(); + } +} \ No newline at end of file diff --git a/test/app/models/Checkin.java b/test/app/models/Checkin.java new file mode 100644 index 0000000..625201b --- /dev/null +++ b/test/app/models/Checkin.java @@ -0,0 +1,22 @@ +package models; + +import javax.persistence.Entity; + +import play.utils.HTML; + +@Entity +public class Checkin extends Post { + + public Checkin(Postable postedObj, User author, String location, String name, + String address) { + super(postedObj, author, ""); + StringBuilder sb = new StringBuilder(HTML.htmlEscape(play.i18n.Messages + .get("checkin.checkedinat") +name + "\n" + address + "\n")); + sb.append(""); + this.content = sb.toString(); + } + +} diff --git a/test/app/models/Comment.java b/test/app/models/Comment.java new file mode 100644 index 0000000..628744f --- /dev/null +++ b/test/app/models/Comment.java @@ -0,0 +1,26 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import play.db.jpa.*; + +import play.utils.HTML; + +@Entity +public class Comment extends Likeable { + public boolean approved; + + @Lob + public String content; + + @ManyToOne + public Commentable parentObj; + + public Comment(Commentable parentObj, User author, String content) { + super(author); + this.parentObj = parentObj; + this.content = HTML.htmlEscape(content); + this.approved = false; + } +} \ No newline at end of file diff --git a/test/app/models/Commentable.java b/test/app/models/Commentable.java new file mode 100644 index 0000000..e5a9486 --- /dev/null +++ b/test/app/models/Commentable.java @@ -0,0 +1,39 @@ +package models; + +import java.util.*; + +import javax.persistence.*; +import play.db.jpa.*; + +@Entity +public abstract class Commentable extends Likeable { + @OneToMany(mappedBy="parentObj", cascade=CascadeType.ALL) + public List comments; + + public Commentable(User owner) { + super(owner); + } + + public Commentable(User owner, Visibility v) { + super(owner, v); + } + + public Commentable addComment(User author, String content) { + Comment newComment = new Comment(this, author, content).save(); + this.comments.add(newComment); + this.save(); + return this; + } + + public List getComments(){ + return Comment.find("FROM Comment c WHERE c.parentObj = ? ORDER BY c.updatedAt DESC", this).fetch(); + } + + public List getOlderComments(int n){ + return Comment.find("FROM Comment c WHERE c.parentObj = ? order by c.updatedAt desc", this).fetch(n); + } + + public List getSomeComments(int n){ + return Comment.find("FROM Comment c WHERE c.parentObj = ? order by c.updatedAt desc", this).fetch(n); + } +} diff --git a/test/app/models/Employment.java b/test/app/models/Employment.java new file mode 100644 index 0000000..74cfd0a --- /dev/null +++ b/test/app/models/Employment.java @@ -0,0 +1,28 @@ +package models; + +import java.util.Date; + +import javax.persistence.*; + +import play.db.jpa.*; + +@Entity +public class Employment extends Model { + @ManyToOne + public Profile employee; + public String employer; + Location location; + public String position; + public Date start_date; + public Date end_date; + + public Employment(String employer){ + //this.employee = employee; + this.employer = employer; +} + + public String toString() + { + return employer; + } +} \ No newline at end of file diff --git a/test/app/models/Enrollment.java b/test/app/models/Enrollment.java new file mode 100644 index 0000000..b3db8a1 --- /dev/null +++ b/test/app/models/Enrollment.java @@ -0,0 +1,30 @@ +package models; + +import java.util.Date; + +import javax.persistence.*; + +import play.db.jpa.*; + +@Entity +public class Enrollment extends Model { + @ManyToOne + public Profile student; + + public String name; + public String type; + public Date year; + public String degree; + public String concentration; // array! + public String classes; // array! + + + public Enrollment(String name){ + this.name = name; +} + + public String toString() + { + return name; + } +} diff --git a/test/app/models/Event.java b/test/app/models/Event.java new file mode 100644 index 0000000..ae91ba7 --- /dev/null +++ b/test/app/models/Event.java @@ -0,0 +1,129 @@ +package models; + +import java.util.*; + +import javax.persistence.Entity; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +@Entity +public class Event extends Postable implements Comparable{ + + @ManyToOne + public User owner; + + public String name; + public String script; + public String location; + public Date startDate; + public Date endDate; + public boolean givenEndDate = false; + + public String privilege; + public boolean open = false; + public boolean friends = false; + public boolean inviteOnly = false; + + @ManyToMany + @JoinTable(name="InvitedRepliedEventMembers") + public Set invited; + + @ManyToMany + @JoinTable(name="InvitedEventMembers") + public Set awaitreply; + + @ManyToMany + @JoinTable(name="EventMembers") + public Set members; + + @ManyToMany + @JoinTable(name="MaybeEventMembers") + public Set maybe; + + @ManyToMany + @JoinTable(name="DeclinedEventMembers") + public Set declined; + + public Event(User author, String name, String script, String location) { + this.owner = author; + this.name = name; + this.script = script; + this.location = location; + this.invited = new HashSet(); + this.awaitreply = new HashSet(); + this.members = new HashSet(); + this.maybe = new HashSet(); + this.declined = new HashSet(); + this.members.add(owner); + } + + public List getPosts() { + return posts; + } + + public void inviteMember(User u){ + if (!invited.contains(u)){ + invited.add(u); + awaitreply.add(u); + } + } + + public void addMember(User u) { + if (!members.contains(u)) + members.add(u); + if(maybe.contains(u)) + maybe.remove(u); + if(declined.contains(u)) + declined.remove(u); + if(awaitreply.contains(u)) + awaitreply.remove(u); + } + + public void addMaybe(User u) { + if (!maybe.contains(u)) + maybe.add(u); + if(members.contains(u)) + members.remove(u); + if(declined.contains(u)) + declined.remove(u); + if(awaitreply.contains(u)) + awaitreply.remove(u); + } + + public void removeMember(User u) { + if (members.contains(u)) + members.remove(u); + if(maybe.contains(u)) + maybe.remove(u); + if(!declined.contains(u)) + declined.add(u); + if(awaitreply.contains(u)) + awaitreply.remove(u); + } + + public int getMemberCount() { + return members.size(); + } + + public int getInvitedCount() { + return awaitreply.size(); + } + + public int getMaybeCount() { + return maybe.size(); + } + + public Set uninvitedFriends(User user) { + HashSet ret = new HashSet(user.friends); + ret.removeAll(this.invited);//was members + return ret; + } + + public int compareTo(Event e){ + if (e.startDate == this.startDate)return 0; + else if (e.startDate.before(this.startDate)) return 1; + else return -1; + } +} \ No newline at end of file diff --git a/test/app/models/FThread.java b/test/app/models/FThread.java new file mode 100644 index 0000000..d56fdf3 --- /dev/null +++ b/test/app/models/FThread.java @@ -0,0 +1,59 @@ +package models; + +import java.util.*; + +import javax.persistence.*; + +import play.data.binding.*; +import play.data.validation.*; +import play.db.jpa.Model; + +@Entity +public class FThread extends Commentable +{ + + @Required + public String title; + + @Required + @As("yyyy-MM-dd") + public Date postedAt; + + @Required + @ManyToOne + public Category category; + + @Required + @Lob + public String content; + + public FThread(Category category, String title, User author, Date postedAt, + String content) + { + super(author); + this.title = title; + this.postedAt = new Date(); + this.content = content; + this.category = category; + this.category.latest = this; + } + + public List comments() + { + return Comment.find("parentObj = ? order by createdAt asc", this) + .fetch(); + } + + public Comment last_comment() + { + Comment last = null; + List comments = Comment.find( + "parentObj = ? order by createdAt asc", this).fetch(); + for (Comment elem : comments) + { + last = elem; + } + return last; + } + +} \ No newline at end of file diff --git a/test/app/models/Group.java b/test/app/models/Group.java new file mode 100644 index 0000000..863db7e --- /dev/null +++ b/test/app/models/Group.java @@ -0,0 +1,59 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import controllers.Application; +import models.Post; +import play.db.jpa.*; +import play.data.validation.*; +import play.libs.Crypto; +import play.modules.elasticsearch.annotations.ElasticSearchIgnore; +import play.modules.elasticsearch.annotations.ElasticSearchable; + +@ElasticSearchable +@Entity +public class Group extends Postable { + + @Required + @ManyToOne + public User owner; + + @Required + @Lob + public String groupName; + + @Required + @Lob + public String description; + + @ElasticSearchIgnore + @OneToMany + public List members; + + public Group(User o, String n, String d){ + this.owner= o; + this.groupName= n; + this.description= d; + this.members= new ArrayList(); + this.members.add(o); + } + + public void addMember(User u){ + if(!members.contains(u)) + members.add(u); + } + + public void removeMember(User u){ + if(members.contains(u)) + members.remove(u); + } + + public int getMemberCount(){ + return members.size(); + } + + public List getPosts(){ + return posts; + } +} \ No newline at end of file diff --git a/test/app/models/Language.java b/test/app/models/Language.java new file mode 100644 index 0000000..a3189ca --- /dev/null +++ b/test/app/models/Language.java @@ -0,0 +1,16 @@ +package models; + +import java.util.Date; + +import javax.persistence.Entity; + +import play.db.jpa.*; + +@Entity +public class Language extends Model { + public String name; + + public Language (String name){ + this.name = name; + } +} diff --git a/test/app/models/Likeable.java b/test/app/models/Likeable.java new file mode 100644 index 0000000..d4d1d44 --- /dev/null +++ b/test/app/models/Likeable.java @@ -0,0 +1,73 @@ +package models; + +import java.util.*; + +import javax.persistence.*; + +import play.db.jpa.*; +import play.data.validation.*; + +@Entity +public abstract class Likeable extends Model { + + @Required + @ManyToOne + public User owner; + + public enum Visibility {PRIVATE, FRIENDS, PUBLIC}; + + @Required + public Visibility visibility; + + @Required + @JoinTable(name="whitelist_table") + @ManyToMany() + public Set whitelist; + + @Required + @JoinTable(name="likes_table") + @ManyToMany(cascade = CascadeType.PERSIST) + public Set thoseWhoLike; + + public Likeable(User owner) { + this(owner, Visibility.FRIENDS); + } + + public Likeable(User owner, Visibility v) { + this.thoseWhoLike = new HashSet(); + this.whitelist = new HashSet(); + this.visibility = v; + this.owner = owner; + this.whitelist.add(owner); + } + + public boolean addLike(User user) { + thoseWhoLike.add(user); + boolean changed = user.likes.add(this); + this.save(); + return changed; + } + + public boolean removeLike(User user) { + thoseWhoLike.remove(user); + boolean changed = user.likes.remove(this); + this.save(); + return changed; + } + + public boolean likedBy(User user) { + return thoseWhoLike.contains(user); + } + + public int numLikes() { + return thoseWhoLike.size(); + } + + public boolean visible(User user) { + if(visibility == Visibility.PRIVATE) + return user.equals(owner); + if(visibility == Visibility.FRIENDS) + return user.equals(owner) || user.isFriendsWith(owner); + return true; + } +} diff --git a/test/app/models/Link.java b/test/app/models/Link.java new file mode 100644 index 0000000..4a6c68a --- /dev/null +++ b/test/app/models/Link.java @@ -0,0 +1,35 @@ +package models; + +import java.util.*; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import javax.persistence.*; + +import play.db.jpa.*; + +@Entity +public class Link extends Post { + enum source {VIDEO}; + private static final Pattern youtube_pattern = Pattern.compile(""); + private static final Pattern vimeo_pattern = Pattern.compile(""); + + public String external_url; + public source link_type; + + + public Link (User user, String content, String url){ + super(user, user, content); + this.external_url = parseLink(url); + } + + private String parseLink(String content){ + Matcher youtube = youtube_pattern.matcher(content); + Matcher vimeo = vimeo_pattern.matcher(content); + + this.link_type = source.VIDEO; + return content; + } + + +} diff --git a/test/app/models/Location.java b/test/app/models/Location.java new file mode 100644 index 0000000..6d611c5 --- /dev/null +++ b/test/app/models/Location.java @@ -0,0 +1,20 @@ +package models; + +import java.util.Date; + +import javax.persistence.Entity; + +import play.db.jpa.*; + +@Entity +public class Location extends Model { + String location; + + public Location(String name){ + location = name; + } + + public String toString(){ + return location; + } +} diff --git a/test/app/models/Message.java b/test/app/models/Message.java new file mode 100644 index 0000000..69fd074 --- /dev/null +++ b/test/app/models/Message.java @@ -0,0 +1,38 @@ +package models; + +import java.util.ArrayList; +import javax.persistence.Entity; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; + +@Entity +public class Message extends Commentable { + + @Lob + public String content; + + @ManyToOne + public User recipient; + + public boolean read; + + public Message(User author, User recipient, String content) { + super(author); + this.recipient = recipient; + this.content = content; + this.comments = new ArrayList(); + read = false; + } + public Comment getRecent() { + if (this.comments.isEmpty()) + return null; + return this.comments.get(this.comments.size() - 1); + } + + @Override + public Commentable addComment(User owner, String content) { + read = false; + return super.addComment(owner, content); + } + +} diff --git a/test/app/models/Model.java b/test/app/models/Model.java new file mode 100644 index 0000000..d7b25ca --- /dev/null +++ b/test/app/models/Model.java @@ -0,0 +1,31 @@ +package models; + +import java.util.Date; + +import javax.persistence.MappedSuperclass; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; + +import play.modules.elasticsearch.annotations.ElasticSearchIgnore; + +@MappedSuperclass +public class Model extends play.db.jpa.Model { + + @ElasticSearchIgnore + public Date createdAt; + @ElasticSearchIgnore + public Date updatedAt; + + @PrePersist + void onPrePersist() { + if (this.createdAt == null) { + this.createdAt = new Date(); + } + this.updatedAt = this.createdAt; + } + + @PreUpdate + void onPreUpdate() { + this.updatedAt = new Date(); + } +} diff --git a/test/app/models/Note.java b/test/app/models/Note.java new file mode 100644 index 0000000..de3a02b --- /dev/null +++ b/test/app/models/Note.java @@ -0,0 +1,53 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import controllers.Security; + +import play.db.jpa.*; +import play.modules.elasticsearch.annotations.ElasticSearchable; + +/* + * Author: Andy Eskridge + * email: andy.eskridge@gmail.com + */ + +@Entity +public class Note extends Status { + + public String title; + + @Lob + public String text; + + private static final int TEASER_LENGTH = 150; + + public Note(User author, String title, String content) { + super(author, content); + this.title = title; + this.text = content; + } + + public String contentTeaser() { + if (this.content.length() < TEASER_LENGTH) { + return this.content; + } else { + return this.content.substring(0, TEASER_LENGTH); + } + } + + public Post previous() { + return Post.find("owner = ? AND date < ? order by date desc", + this.owner, this.createdAt).first(); + } + + public Post next() { + return Post.find("date > ? order by date asc", this.createdAt) + .first(); + } + + public boolean byCurrentUser() { + return owner.email.equals( Security.connected() ); + } +} diff --git a/test/app/models/Page.java b/test/app/models/Page.java new file mode 100644 index 0000000..9fb01fd --- /dev/null +++ b/test/app/models/Page.java @@ -0,0 +1,41 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import org.elasticsearch.index.query.QueryBuilders; +import controllers.Application; +import controllers.Skins; +import controllers.Users; +import play.db.jpa.*; +import play.modules.elasticsearch.*; +import play.modules.elasticsearch.annotations.ElasticSearchable; +import play.modules.elasticsearch.search.SearchResults; +import play.libs.Crypto; + +@Entity +public class Page extends Postable { + + @OneToOne + public User admin; + + @Lob + public String info; + public String title; + + public Long profilePhoto; + + @OneToMany + public List photos; + + public Page(User user, String newTitle, String newInfo){ + this.admin = user; + this.title = newTitle; + this.info = newInfo; + } + + public List getPosts(){ + return posts; + } + +} diff --git a/test/app/models/Photo.java b/test/app/models/Photo.java new file mode 100644 index 0000000..d025e00 --- /dev/null +++ b/test/app/models/Photo.java @@ -0,0 +1,100 @@ +package models; + +import java.awt.image.*; +import java.io.*; +import java.util.*; +import javax.imageio.ImageIO; +import javax.persistence.*; +import play.libs.*; +import play.db.jpa.*; +import play.data.validation.*; +import net.coobird.thumbnailator.*; +import net.coobird.thumbnailator.geometry.*; +import net.coobird.thumbnailator.name.*; + +@Entity +public class Photo extends Commentable { + + public static final int MAX_PIXEL_SIZE = 1024; + + @Required + public Blob image; + + public String caption; + + @Required + public Blob thumbnail120x120, + thumbnail50x50, + thumbnail30x30; + + public Photo(User owner, File image) throws IOException, + FileNotFoundException { + this(owner, image, null); + } + + public Photo(User owner, File image, String caption) + throws IOException, + FileNotFoundException { + super(owner); + this.caption = caption; + shrinkImage(image); + this.image = fileToBlob(image); + this.createThumbnails(); + } + + public void updateImage(File image) throws IOException, + FileNotFoundException { + shrinkImage(image); + this.image = fileToBlob(image); + this.createThumbnails(); + } + + private void createThumbnails() throws IOException { + this.thumbnail120x120 = this.createThumbnailBlob(120, 120); + this.thumbnail50x50 = this.createThumbnailBlob(50, 50); + this.thumbnail30x30 = this.createThumbnailBlob(30, 30); + } + + private Blob createThumbnailBlob(int width, int height) throws IOException { + File image = this.image.getFile(); + File thumbnail = Thumbnails.of(image) + .size(width, height) + .crop(Positions.CENTER) + .outputQuality(1.0) + .asFiles(Rename.NO_CHANGE) + .get(0); + return fileToBlob(thumbnail); + } + + /** + * Shrink the image to MAX_PIXEL_SIZE if necessary. + * + * @param image the file to convert. + * @throws IOException + */ + private static void shrinkImage(File image) throws IOException { + BufferedImage bufferedImage = ImageIO.read(image); + if (bufferedImage != null && (bufferedImage.getWidth() > MAX_PIXEL_SIZE || + bufferedImage.getHeight() > MAX_PIXEL_SIZE)) { + Thumbnails.of(image) + .size(MAX_PIXEL_SIZE, MAX_PIXEL_SIZE) + .outputQuality(1.0) + .toFile(image); + } + } + + /** + * Convert a given File to a Photo model. + * + * @param image the file to convert. + * @return the newly created Photo model. + * @throws FileNotFoundException + */ + private static Blob fileToBlob(File image) throws FileNotFoundException { + Blob blob = new Blob(); + blob.set(new FileInputStream(image), + MimeTypes.getContentType(image.getName())); + return blob; + } +} + diff --git a/test/app/models/Post.java b/test/app/models/Post.java new file mode 100644 index 0000000..cfa5141 --- /dev/null +++ b/test/app/models/Post.java @@ -0,0 +1,91 @@ +package models; + +import java.util.*; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import play.utils.HTML; + +import javax.persistence.*; + +import controllers.Security; + +import play.db.jpa.*; +import play.modules.elasticsearch.annotations.ElasticSearchable; + + +@Entity +public class Post extends Commentable { + + private static final Pattern links_pattern = Pattern.compile("\\b?[@#]\\w+\\b"); + + @ManyToOne + public Postable postedObj; // The postable object this post was posted on. + + @ManyToMany(cascade=CascadeType.PERSIST) + public Set tags; + + @ManyToMany(cascade=CascadeType.PERSIST) + public List mentions; + + @Lob + public String content; + + private static final int TEASER_LENGTH = 150; + + public Post(Postable postedObj, User author, String content) { + super(author); + this.postedObj = postedObj; + this.tags = new TreeSet(); + this.mentions = new ArrayList(); + this.content = parseContent(HTML.htmlEscape(content)); + } + + public String contentTeaser() { + return this.content.length() < TEASER_LENGTH ? this.content : this.content.substring(0, TEASER_LENGTH); + } + + public Post previous() { + return Post.find("owner = ? AND date < ? order by date desc", + this.owner, this.createdAt).first(); + } + + public Post next() { + return Post.find("date > ? order by date asc", this.createdAt) + .first(); + } + + public String parseContent(String unlinked_content){ + Matcher links_matcher = links_pattern.matcher(unlinked_content); + + while(links_matcher.find() ){ + String match = links_matcher.group(); + if(match.startsWith("#")) { // tag + String tag = match.substring(1); + Tag newTag = Tag.findOrCreateByName(tag); + tags.add(newTag); + unlinked_content = unlinked_content.replace(match, ("" + match + "")); + } + else if(match.startsWith("@")) { // mention + User newMention = User.find("byUsername", match.substring(1)).first(); + if(newMention != null){ + unlinked_content = unlinked_content.replace(match, ("" + newMention.name + "")); + mentions.add(newMention); + } + } + else + System.out.print("Error occured"); // not good + } + return unlinked_content; + } + + + // What is this used for? + public static List findTaggedWith(String... tags) { + return Status.find("select distinct p from Status p join p.tags as t where t.name in (:tags) group by p.id, p.owner, p.message, p.update_time having count(t.id) = :size" + ).bind("tags", tags).bind("size", tags.length).fetch(); + } + + public static List findVisible(User user) { + return Post.find("SELECT DISTINCT p FROM Post AS p LEFT JOIN p.whitelist AS whitelist LEFT JOIN p.owner.friends AS friends WHERE (p.owner = ?1) OR (p.visibility = ?2) OR (?1 IN whitelist) OR (p.visibility = ?3 AND ?1 IN friends) ORDER BY p.updatedAt DESC", user, Visibility.PUBLIC, Visibility.FRIENDS).fetch(); + } +} \ No newline at end of file diff --git a/test/app/models/Postable.java b/test/app/models/Postable.java new file mode 100644 index 0000000..b4ef636 --- /dev/null +++ b/test/app/models/Postable.java @@ -0,0 +1,25 @@ +package models; + +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.OneToMany; +import play.modules.elasticsearch.annotations.ElasticSearchIgnore; + +@Entity +abstract class Postable extends Model { + + @ElasticSearchIgnore + @OneToMany(mappedBy="postedObj", cascade=CascadeType.ALL) + public List posts; + + public List getPosts() { + return posts; + } + + public Postable addPost(User author, String content) { + new Post(this, author, content).save(); + return this; + } +} diff --git a/test/app/models/Profile.java b/test/app/models/Profile.java new file mode 100644 index 0000000..146b142 --- /dev/null +++ b/test/app/models/Profile.java @@ -0,0 +1,158 @@ +package models; + +import java.io.*; +import java.util.*; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +import play.data.validation.*; + +import utils.Bootstrap; + +import controllers.Photos; +import controllers.Skins; + +@Entity +public class Profile extends Model { + @OneToOne(cascade=CascadeType.ALL) + public User owner; + + public String gender; // The user's gender:female or male + public String locale; // The user's locale (ISO Language Code and ISO Country + public String gravatarEmail; + + @OneToOne + public User significantOther; // The user's significant other + @Match("\\^\\(0\\[1-9\\]\\|1\\[012\\]\\)\\[-/.\\]\\(0\\[1-9\\]\\|\\[12\\]\\[0-9\\]\\|3\\[01\\]\\)\\[-/.\\]\\(19\\|20\\)\\d\\d\\$") + public Date anniversary; // date of anniversary + + public String bio; // The user's biography + public String interestedIn; //genders the user is intersted in: Male, Female, Both, Neither + + @OneToOne + public Photo profilePhoto; // The user's profile picture. + @OneToOne + public Photo gravatarPhoto; + + @Match("\\^\\(0\\[1-9\\]\\|1\\[012\\]\\)\\[-/.\\]\\(0\\[1-9\\]\\|\\[12\\]\\[0-9\\]\\|3\\[01\\]\\)\\[-/.\\]\\(19\\|20\\)\\d\\d\\$") + public Date birthday; // The user's birthday, uses JQuery UI + + @ManyToOne + public Location location; // The user's current city + + @ManyToOne + public Location hometown; // The user's hometown + + // not implemented yet!! + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL) + public List languages; // The user's languages + + public String political; // The user's political view + public String quotes; // The user's favorite quotes + + public enum Relationship { + SINGLE ("Single"), + ENGAGED ("Engaged"), + MARRIED ("Married"), + ITSCOMPLICATED ("It's complicated"), + OPEN ("Open relationship"), + WIDOWED ("Widowed"), + SEPERATED ("Seperated"), + DIVORCED ("Divorced"), + CIVILUNION ("Civil union"), + DOMESTIC ("Domestic partnership"); + + private final String text; + Relationship(String text) { + this.text = text; + } + + public String toString() { + return text; + } + + public static Relationship fromString(String text) { + for (Relationship r : Relationship.values()) + if (r.text.equalsIgnoreCase(text)) + return r; + return null; + } + } + public Relationship relationshipStatus; // The user's relationship + + private static final Relationship[] singleArray = {Relationship.SINGLE, Relationship.ITSCOMPLICATED, Relationship.WIDOWED, Relationship.SEPERATED, Relationship.DIVORCED}; + public static final HashSet single = new HashSet(Arrays.asList(singleArray)); + + // status:Single,In a relationship, Engaged,Married,It's + // complicated,In an open relationship,Widowed,Separated,Divorced,In + // a civil union,In a domestic partnership + + public String religion; // The user's religious views + + @OneToMany(mappedBy = "student", cascade = CascadeType.ALL) + public List education; // A list of the user's education history + + @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL) + public List work; // A list of the user's work history + + @ManyToOne + public Skin skin;//Skin (StyleSheet) used by this Profile + + @OneToMany(mappedBy = "subscriber", cascade = CascadeType.ALL) + public List feeds; + + //CONTACT INFORMATION + @Phone public String phone; // the user's phone number + public String address; // the user's address + public String website; // the user's website + public String email; //the user's email + + public boolean hasAnniversary() { + return !single.contains(relationshipStatus); + } + + public Profile(User owner) { + this.anniversary = null; + this.bio = ""; + this.birthday = null; + this.interestedIn = ""; + this.relationshipStatus = Relationship.SINGLE; + this.gender = ""; + this.hometown = null; + this.location = null; + this.owner = owner; + this.political = ""; + this.quotes = ""; + this.significantOther = null; + this.religion = ""; + + this.languages = new ArrayList(); + this.education = new ArrayList(); + this.work = new ArrayList(); + this.feeds = new ArrayList(); + this.skin = Skins.getSkin("default","default_skin");//the default skin look is used + this.phone = ""; + this.address = ""; + this.website = ""; + this.email = ""; + User defaultUser = User.find("username= ?", "default").first(); + this.profilePhoto = Photo.find("owner=? AND caption=?",defaultUser, "Default Profile Photo").first(); + this.gravatarPhoto = null; + this.gravatarEmail = owner.email; + } + + public Profile(User owner, String bio, String gender, String quotes, String phone, String website) { + this.owner = owner; + this.bio = bio; + this.gender = gender; + this.phone = phone; + this.quotes = quotes; + this.website = website; + User defaultUser = User.find("username= ?", "default").first(); + this.profilePhoto = Photo.find("owner=? AND caption=?",defaultUser, "Default Profile Photo").first(); + } +} diff --git a/test/app/models/Question.java b/test/app/models/Question.java new file mode 100644 index 0000000..387e49e --- /dev/null +++ b/test/app/models/Question.java @@ -0,0 +1,44 @@ +package models; + +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import play.data.validation.Required; + +@Entity +public class Question extends Post{ + + @Required + @ManyToOne + @JoinTable(name="QuestionsToUser") + public User owner; + + @Required + @OneToMany(mappedBy="question") + public Set answers; + + public Question(User author, String question) { + super(author, author, question); + this.owner = author; + } + + public void addUserAnswer(User user, Answer answer){ + if(!answer.usersWhoAnswered.contains(user)) + answer.addUserChoice(user); + answer.save(); + this.save(); + } + + // Return the number of user answers for this question + public int totalUserAnswers(){ + int result = 0; + for(Answer a : answers) + result += a.numTimesAnswered(); + return result; + } + +} diff --git a/test/app/models/RSSFeed.java b/test/app/models/RSSFeed.java new file mode 100644 index 0000000..62c9242 --- /dev/null +++ b/test/app/models/RSSFeed.java @@ -0,0 +1,214 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import controllers.Secure; + +import controllers.Comments; +import controllers.Secure; +import play.db.jpa.*; +import play.data.validation.*; + + +import play.libs.WS; + + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.NamedNodeMap; + + + +@Entity +@Table(uniqueConstraints = @UniqueConstraint( + columnNames={"SUBSCRIBER", "URL"})) +public class RSSFeed extends Model { + + @Required + @ManyToOne + @JoinColumn(name="SUBSCRIBER") + public User subscriber; + @Required + public String url; + @Required + public boolean is_valid; + + public RSSFeed(User subscriber, String url) { + this.subscriber = subscriber; + this.url = url; + this.is_valid = this.validateURL(); + } + + + public List getNodesByName(String name) { + List list = new ArrayList(); + + Document xml = getXML(); + if(xml != null){ + NodeList nodes = xml.getElementsByTagName(name); + for(int i=0; i<=nodes.getLength(); i++) { + if (nodes.item(i) == null) + continue; + list.add(new RSSFeedNode(nodes.item(i))); + } + + } + return list; + } + + public RSSFeedNode getFirstNodeByName(String name) { + if(getNodesByName(name).size()>0) + return getNodesByName(name).get(0); + return null; + } + + public List getItems() { + return getNodesByName("item"); + } + + public List getItems(int num) { + List list = getItems(); + return (list.size() < num ? list : list.subList(0, num)); + } + + public String getTitle() { + if(getFirstNodeByName("channel")!=null) + return getFirstNodeByName("channel").ccontent("title"); + return null; + } + + public String getChannelLink() { + if(getFirstNodeByName("channel")!=null) + return getFirstNodeByName("channel").ccontent("link"); + return null; + } + + public RSSFeedNode getImageNode() { + return getFirstNodeByName("image"); + } + public String getImageNodeURL() { + if(getFirstNodeByName("image") != null) + return getFirstNodeByName("image").ccontent("url"); + return ""; + } + public String getImageNodeWidth() { + if(getFirstNodeByName("image") != null) + return getFirstNodeByName("image").ccontent("width"); + return ""; + } + public String getImageNodeHeight() { + if(getFirstNodeByName("image") != null) + return getFirstNodeByName("image").ccontent("height"); + return ""; + } + + public Document getXML() { + try { + Document xml = WS.url(this.url).get().getXml(); + if (!this.is_valid) { + this.is_valid = validXML(xml); + this.save(); + } + return xml; + } catch(Exception e) { + return null; + } + } + + public boolean validateURL() { + try { + Document xml = WS.url(this.url).get().getXml(); + return validXML(xml); + } catch(Exception e) { + return false; + } + } + + private boolean validXML(Document xml) { + try { + Node rss_node = xml.getElementsByTagName("rss").item(0); + + NamedNodeMap attribs = rss_node.getAttributes(); + Node version_node = attribs.getNamedItem("version"); + String version = version_node.getTextContent(); + + return version.startsWith("2."); + } catch(Exception e) { + return false; + } + } + + public class RSSFeedNode { + private Node n; + + RSSFeedNode(Node n) { + this.n = n.cloneNode(true); + } + + public String attr(String attr_name) { + NamedNodeMap attribs = this.n.getAttributes(); + Node attrib_node = attribs.getNamedItem(attr_name); + if (attrib_node == null) { + return null; + } + return attrib_node.getTextContent(); + } + + public void traverse() { + traverse(this.n, 0); + } + + // For debuggin' + private void traverse(Node n, int indent) { + for(int i=0; i 15) { + val = val.substring(0, 15); + } + System.out.println(n.getNodeName()+" ["+(val==null?null:val.trim())+"]"); + + NodeList children = n.getChildNodes(); + for (int i=0; i relevant_nodes = new ArrayList(); + for(int i=0; i values + * + * Differences in Skins are in how they use the template main.css + * Variables will include: + * color + * size + * shape + * (more to be added) + * + * From discussion with Professor: No other templates will be added. + * The only changes in Skin will be to variables within main.css + * + * + * For colors in HTML: look at http://www.w3schools.com/html/html_colornames.asp + * + */ +@Entity +public class Skin extends Model { + + public String userName;//creator's UserName + public String skinName;//the skin's name + + public String isPublic;//whether or not this skin is public + + @OneToMany(mappedBy = "attachedSkin", cascade = CascadeType.ALL) + public List parameters; // attributes of the skin + + /** + * addParam (helper method for constructor + */ + private void addParam(String key, String value) + { + SkinPair param = new SkinPair(this,key,value).save(); + this.parameters.add(param); + } + + public Skin(String uN, String sN) + { + this.userName = uN; + this.skinName = sN; + parameters = new ArrayList(); + isPublic = "false"; + this.save(); + } + + + /** + * cloneSkin + * @param c Skin to clone + * clones attributes from skin c to this Skin + */ + public void cloneSkin(Skin c) + { + //body + List parameters = SkinPair.find("attachedSkin = ?",c).fetch(); + for(SkinPair update : parameters) + { + this.addParam(update.name,update.value); + } + } + + /** + * get + * @param String key + * @return value associated to key in parameters + */ + public String get(String key) + { + SkinPair param = SkinPair.find("attachedSkin = ? AND name = ?",this,key).first(); + if(param != null) + return param.value; + else + return null; + } + + /** + * setParam + * @param key (name of param to change) + * @param value (updated value) + * Change param to update value. + * NOTE: if value is updated to a bad value, will get this value, + * but the .css file will not interpret this value, and will give a default of null + * for the attribute the value is attached to. + */ + public void setParam(String key, String value) + { + SkinPair s = SkinPair.find("attachedSkin = ? AND name = ?", this, key).first(); + + if(s == null) + { + //s is null so it doesn't exist in the skin, so we make it + addParam(key,""); + s = SkinPair.find("attachedSkin = ? AND name = ?", this, key).first(); + } + + if(!value.equalsIgnoreCase(s.value)){ + + + + //take out photo so the color can be seen only if color is changed + if(key.equals("headerBGColor") && + !value.equalsIgnoreCase("none") && + !value.equalsIgnoreCase("FFFFFF") && + !value.equalsIgnoreCase("white"))//don't want white + { + SkinPair headerBGPhoto = SkinPair.find("attachedSkin = ? AND name = ?", this, "headerBGPhoto").first(); + if(headerBGPhoto == null) + { + addParam("headerBGPhoto","none"); + headerBGPhoto = SkinPair.find("attachedSkin = ? AND name = ?", this, "headerBGPhoto").first(); + } + headerBGPhoto.value = "none"; + headerBGPhoto.save(); + } + + + + s.value = value; + s.save(); + } + + + } + + + +} diff --git a/test/app/models/SkinPair.java b/test/app/models/SkinPair.java new file mode 100644 index 0000000..ee5eb4b --- /dev/null +++ b/test/app/models/SkinPair.java @@ -0,0 +1,32 @@ +package models; + +import java.lang.reflect.Field; +import java.util.*; +import javax.persistence.*; + +import controllers.Security; +import play.db.jpa.*; + + +/** + * SkinPair + * @author Lauren Yew + * + * these are the attributes for a Skin + */ +@Entity +public class SkinPair extends Model { + + @ManyToOne + public Skin attachedSkin; + + public String name; + public String value; + + public SkinPair(Skin s, String n, String v) + { + this.attachedSkin = s; + this.name = n; + this.value = v; + } +} \ No newline at end of file diff --git a/test/app/models/Status.java b/test/app/models/Status.java new file mode 100644 index 0000000..050c3c8 --- /dev/null +++ b/test/app/models/Status.java @@ -0,0 +1,60 @@ +package models; + +import java.util.*; +import javax.persistence.*; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import play.db.jpa.*; +import play.data.validation.*; + +@Entity +public class Status extends Commentable { + + private static final Pattern links_pattern = Pattern.compile("\\b?[@#]\\w*\\b"); + // private static final Pattern youtube_pattern = Pattern.compile(); + // private static final Pattern vimeo_pattern = Pattern.compile(); + + + @Lob + public String content; + + @ManyToMany(cascade=CascadeType.PERSIST) + public List tags; + + @ManyToMany(cascade=CascadeType.PERSIST) + public List mentions; + + public Status(User author, String content) { + super(author); + this.comments = new ArrayList(); + this.tags = new ArrayList(); + this.mentions = new ArrayList(); + this.content = content; + } + + public String parseContent(String unlinked_content){ + Matcher links_matcher = links_pattern.matcher(unlinked_content); + + while(links_matcher.find() ){ + String match = links_matcher.group(); + if(match.startsWith("#")) { // tag + String newTag = match.substring(1); + tags.add(Tag.findOrCreateByName(newTag)); + } + else if(match.startsWith("@")) { // mention + User newMention = User.find("byUsername", match.substring(1)).first(); + mentions.add(newMention); + } + else + System.out.print("Error occured"); + } + return unlinked_content; + } + + + public static List findTaggedWith(String... tags) { + return Status.find("select distinct p from Status p join p.tags as t where t.name in (:tags) group by p.id, p.owner, p.message, p.update_time having count(t.id) = :size" + ).bind("tags", tags).bind("size", tags.length).fetch(); + } +} diff --git a/test/app/models/Subscription.java b/test/app/models/Subscription.java new file mode 100644 index 0000000..76a0b8c --- /dev/null +++ b/test/app/models/Subscription.java @@ -0,0 +1,22 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import play.db.jpa.*; + +@Entity +public class Subscription extends Model { + + @ManyToOne + public User subscribed; + + @ManyToOne + public User subscriber; + + public Subscription(User subscribed, User subscriber) { + this.subscribed = subscribed; + this.subscriber = subscriber; + } + +} diff --git a/test/app/models/Tag.java b/test/app/models/Tag.java new file mode 100644 index 0000000..2dbc933 --- /dev/null +++ b/test/app/models/Tag.java @@ -0,0 +1,34 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import play.db.jpa.*; +import play.data.validation.*; + +@Entity +public class Tag extends Model implements Comparable { + + @Required + public String name; + + private Tag(String name) { + this.name = name; + } + + public String toString() { + return name; + } + + public int compareTo(Tag otherTag) { + return name.compareTo(otherTag.name); + } + + public static Tag findOrCreateByName(String name) { + Tag tag = Tag.find("byName", name).first(); + if(tag == null) { + tag = new Tag(name); + } + return tag; + } +} diff --git a/test/app/models/TempUser.java b/test/app/models/TempUser.java new file mode 100644 index 0000000..96dab51 --- /dev/null +++ b/test/app/models/TempUser.java @@ -0,0 +1,27 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import play.libs.Crypto; + +@Entity +public class TempUser extends Model { + public String first_name; // The user's first name + public String last_name; // The user's last name + public String username; // The user's username + public boolean verified; // The user's account verification status, + public String email; // The proxied or contact email address granted by the + public String password; + public String UUID; + + public TempUser(String email, String password, String username, String first_name, String last_name, String UUID) { + this.email = email; + this.password = Crypto.passwordHash(password); + this.username = username; + this.first_name = first_name; + this.last_name = last_name; + this.UUID = UUID; + verified = false; + } +} \ No newline at end of file diff --git a/test/app/models/TimelineModel.java b/test/app/models/TimelineModel.java new file mode 100644 index 0000000..0612881 --- /dev/null +++ b/test/app/models/TimelineModel.java @@ -0,0 +1,31 @@ +package models; + +import javax.persistence.*; +import play.db.jpa.*; +import play.data.validation.*; +import java.util.Date; +import java.util.Vector; + +@Entity +public class TimelineModel extends Model{ + public enum Action { + CREATE, MODIFY, DELETE + }; + +@Required +@Lob + private Vector posts; + + public TimelineModel(User auth) { + this.posts = new Vector(); + } + + public Vector getEvents() { + return this.posts; + } + + public void addEvent(long userid, Object o, TimelineModel.Action action, Vector participants, String description) { + this.posts.add(new Post((User)User.findById(userid), (User)User.findById(userid), description)); + this.save(); + } +} \ No newline at end of file diff --git a/test/app/models/User.java b/test/app/models/User.java new file mode 100644 index 0000000..5db7924 --- /dev/null +++ b/test/app/models/User.java @@ -0,0 +1,390 @@ +package models; + +import java.util.*; + +import javax.persistence.*; + +import org.elasticsearch.index.query.QueryBuilders; +import controllers.Application; +import controllers.Messages; +import controllers.Skins; +import controllers.Users; +import play.db.jpa.*; +import play.modules.elasticsearch.*; +import play.modules.elasticsearch.annotations.ElasticSearchIgnore; +import play.modules.elasticsearch.annotations.ElasticSearchable; +import play.modules.elasticsearch.search.SearchResults; +import play.libs.Crypto; +import utils.Bootstrap; + +@ElasticSearchable +@Entity +public class User extends Postable { + + public String name; // The user's full name + public String first_name; // The user's first name + public String middle_name; // The user's middle name + public String last_name; // The user's last name + + // Code) + + public String username; // The user's username + + @ElasticSearchIgnore + public double timezone; // The user's timezone offset from UTC + + @ElasticSearchIgnore + public Date updated_time; // The last time the user's profile was updated; + // changes to the + // languages, link, timezone, verified, + // interested_in, favorite_athletes, favorite_teams, + // andvideo_upload_limits are not not reflected in + // this value + + + public boolean verified; // The user's account verification status, + // either true or false(see below) + + public String email; // The proxied or contact email address granted by the + // user + + @ManyToOne + public Skin skin;//Skin (StyleSheet) used by this User + + public String password; + + // User's basic profile information + @OneToOne(mappedBy="owner") + public Profile profile; + public Profile getProfile(){ + if(profile == null){ + profile = new Profile(this); + profile.save(); + } + if (profile.profilePhoto == null) { + User defaultUser = User.find("username= ?", "default").first(); + profile.profilePhoto = Photo.find("owner=? AND caption=?",defaultUser, "Default Profile Photo").first(); + } + if (profile.skin == null) { + profile.skin = Skins.getSkin("default","default_skin");//the default skin look is used + } + return profile; + } + + + @OneToOne + public TimelineModel timeline; + + @ElasticSearchIgnore + @JoinTable(name="friends_table") + @ManyToMany(cascade = CascadeType.PERSIST) + public Set friends; + + @ElasticSearchIgnore + @JoinTable(name="friend_requests_table") + @ManyToMany(cascade = CascadeType.PERSIST) + public Set friendRequests; // A list of the user's friendship history + + @ElasticSearchIgnore + public boolean subscription; // Whether the user has allowed subscriptions or not + + @ElasticSearchIgnore + @OneToMany(mappedBy = "subscriber", cascade = CascadeType.ALL) + public List subscribedTo; // A list of subscriptions the user subscribed to + + @ElasticSearchIgnore + @OneToMany(mappedBy = "subscribed", cascade = CascadeType.ALL) + public List subscribers; // A list of subscriptions to the user's subscribers + + @ElasticSearchIgnore + @ManyToMany(mappedBy="thoseWhoLike") + public Set likes; + + @ElasticSearchIgnore + @ManyToMany(mappedBy="usersWhoAnswered") + public Set userAnswers; + + @ElasticSearchIgnore + @OneToMany(mappedBy="owner") + public Set questions; + + @OneToMany(mappedBy = "subscriber", cascade = CascadeType.ALL) + public List feeds; + + + public User(String email, String password, String username) { + this.email = email; + this.password = Crypto.passwordHash(password); + this.username = username; + this.friends = new HashSet(); + this.friendRequests = new HashSet(); + this.save(); + + friends.add(this); + this.save(); + // this.education = new ArrayList(); + } + + public User(String email, String password, String username, String first_name, String last_name) { + this.email = email; + this.password = Crypto.passwordHash(password); + this.username = username; + this.first_name = first_name; + this.last_name = last_name; + this.name = first_name + " " + last_name; + + profile = new Profile(this); + profile.save(); + + this.friends = new HashSet(); + this.friendRequests = new HashSet(); + this.save(); + friends.add(this); + + this.timeline = new TimelineModel(this); + timeline.save(); + this.save(); + // this.education = new ArrayList(); + } + + public User(TempUser user) { + if (user.verified == false) { + this.email = user.email; + this.password = user.password; + this.username = user.username; + this.first_name = user.first_name; + this.last_name = user.last_name; + user.verified = true; + + profile = new Profile(this); + profile.save(); + + this.friends = new HashSet(); + this.friendRequests = new HashSet(); + this.save(); + friends.add(this); + + this.timeline = new TimelineModel(this); + timeline.save(); + this.save(); + } + } + + public static User connect(String login, String password) { + return find("SELECT u FROM User u WHERE (u.email = ?1 OR u.username = ?1) and u.password = ?2", login, Crypto.passwordHash(password)).first(); + } + + public static User getUser(String login) { + return find("SELECT u FROM User u WHERE u.email = ?1 OR u.username = ?1", login).first(); + } + + public List inbox() { + return Message.find("SELECT m FROM Message m WHERE m.recipient = ?1 OR m.owner = ?1", this).fetch(); + } + + public List unreadMessages() { + return Message.find("byRecipientAndRead", this, false).fetch(); + } + + public long unreadCount() { + return Message.find("SELECT m FROM Message m WHERE m.recipient = ?1 AND m.read = false", this).fetch().size(); + } + + public List viewNotes() { + return Note.find("byOwner", this).fetch(); + } + + public List comments() { + return Comment.find("byOwner", this).fetch(); + } + + + public List news() { + return Post.find("SELECT p FROM Post p INNER JOIN p.owner.friends u WHERE u = ?1 AND p.postedObj MEMBER OF User ORDER BY p.updatedAt DESC", this).fetch(); + } + + public List subscriptionNews() { + return Post.find("SELECT p FROM Post p, IN(p.owner.subscribers) u WHERE u.subscriber.id = ?1 and p.postedObj.id = u.subscribed.id order by p.updatedAt desc", + this.id).fetch(); + } + + public void createTimeline() { + if (this.timeline == null) { + this.timeline = new TimelineModel(this); + this.timeline.save(); + this.save(); + } + } + + + /** Get the number of users users who have requested to be friends + * + * @return the number outstanding friend requests + */ + public long numFriendRequests() { + return friendRequests.size(); + } + + public List getGroups(){ + List allGroups= Group.findAll(); + List answer= new ArrayList(); + for(Group g : allGroups){ + for(User u : g.members){ + if(u.equals(this)){ + answer.add(g); + break; + } + } + } + return answer; + } + + public boolean equals(Object obj) { + if (obj == null) + return false; + if (obj == this) + return true; + if (obj.getClass() != getClass()) + return false; + return username.equals(((User) obj).username); + } + + public List getPages(){ + return Page.find("SELECT p FROM Page p WHERE p.admin = ?", this).fetch(); + } + + public String toString(){ + return first_name + " " + last_name; + } + + public boolean isFriendsWith(User user) { + return friends.contains(user); + } + + /** Get all authored events + * + * @return a list of events that User has authored + */ + public List authoredEvents() { + return Event.find("SELECT r FROM Event r where r.owner = ? ORDER BY r.startDate", this).fetch(); + } + + /** Get all upcoming events + * + * @return a list of upcoming events that User has authored + */ + public List upcomingEvents() { + return Event.find("SELECT r FROM Event r where r.owner = ?1 AND r.startDate >= ?2 ORDER BY r.startDate", this, new Date()).fetch(); + } + + /** Get all past events + * + * @return a list of past events that User has authored + */ + public List pastEvents() { + return Event.find("SELECT r FROM Event r where r.owner = ?1 AND r.endDate < ?2 ORDER BY r.startDate", this, new Date()).fetch(); + } + + /** List all past events for any user + * + * @return a list of past events the user is a member of + */ + public List myPastEvents() { + //past events + List allEvents= Event.findAll(); + List allUpcoming = myUpcomingEvents(); + List allToday = todayEvents(); + List answer= new ArrayList(); + for(Event e : allEvents){ + for(User u : e.invited){ + if(u.equals(this) && !allUpcoming.contains(e) && !allToday.contains(e)){ + // if(u.equals(this)){ + answer.add(e); + break; + } + } + } + Collections.sort(answer); + return answer; + } + + /** List all events for any user upcoming + * + * @ return a list of events that haven't happened yet the user is a member of + */ + public List myUpcomingEvents(){ + List allEvents = Event.find("SELECT r FROM Event r where r.startDate > ?", new Date()).fetch(); + List answer= new ArrayList(); + Calendar cal = Calendar.getInstance(); + for(Event e : allEvents){ + for(User u : e.invited){ + if(u.equals(this) && (e.startDate.getDate() != cal.get(Calendar.DAY_OF_MONTH) && e.startDate.getMonth() != cal.get(Calendar.MONTH))){ + answer.add(e); + break; + } + } + } + Collections.sort(answer); + return answer; + } + + /** List all events for any user happening today + * + * @ return a list of events that happen today the user is a member of + */ + public List todayEvents(){ + List allEvents = Event.findAll(); + List answer= new ArrayList(); + Calendar cal = Calendar.getInstance(); + for(Event e : allEvents){ + for(User u : e.invited){ + if(u.equals(this) && (e.startDate.getDate() == cal.get(Calendar.DAY_OF_MONTH) && e.startDate.getMonth() == cal.get(Calendar.MONTH))){ + answer.add(e); + break; + } + } + } + Collections.sort(answer); + return answer; + } + + /** List all events for any user upcoming that the user declined + * + * @ return a list of events that haven't happened yet the user declined + */ + public List myDeclinedEvents(){ + List allEvents = Event.find("SELECT r FROM Event r where r.startDate > ?", new Date()).fetch(); + List answer= new ArrayList(); + Calendar cal = Calendar.getInstance(); + for(Event e : allEvents){ + for(User u : e.declined){ + if(u.equals(this) && (e.startDate.getDate() != cal.get(Calendar.DAY_OF_MONTH) && e.startDate.getMonth() != cal.get(Calendar.MONTH))){ + answer.add(e); + break; + } + } + } + Collections.sort(answer); + return answer; + } + + /** List all declined events for any user happening today + * + * @ return a list of declined events that happen today + */ + public List declinedTodayEvents(){ + List allEvents = Event.findAll(); + List answer= new ArrayList(); + Calendar cal = Calendar.getInstance(); + for(Event e : allEvents){ + for(User u : e.declined){ + if(u.equals(this) && (e.startDate.getDate() == cal.get(Calendar.DAY_OF_MONTH) && e.startDate.getMonth() == cal.get(Calendar.MONTH))){ + answer.add(e); + break; + } + } + } + Collections.sort(answer); + return answer; + } +} diff --git a/test/app/models/UserLanguage.java b/test/app/models/UserLanguage.java new file mode 100644 index 0000000..273ab23 --- /dev/null +++ b/test/app/models/UserLanguage.java @@ -0,0 +1,21 @@ +package models; + +import java.util.Date; + +import javax.persistence.*; + +import play.db.jpa.*; + +@Entity +public class UserLanguage extends Model { + @ManyToOne + public Profile user; + + @ManyToOne + public Language language; + + public UserLanguage(Profile user, Language lang){ + this.user = user; + this.language = lang; + } +} \ No newline at end of file diff --git a/test/app/models/UserPage.java b/test/app/models/UserPage.java new file mode 100644 index 0000000..aecea6c --- /dev/null +++ b/test/app/models/UserPage.java @@ -0,0 +1,29 @@ +package models; + +import java.util.*; +import javax.persistence.*; + +import org.elasticsearch.index.query.QueryBuilders; +import controllers.Application; +import controllers.Skins; +import controllers.Users; +import play.db.jpa.*; +import play.modules.elasticsearch.*; +import play.modules.elasticsearch.annotations.ElasticSearchable; +import play.modules.elasticsearch.search.SearchResults; +import play.libs.Crypto; + +@Entity +public class UserPage extends Model { + + @ManyToOne + public Page page; + + @ManyToOne + public User fan; + + public UserPage(User user, Page page){ + this.fan = user; + this.page = page; + } +} diff --git a/test/app/utils/Bootstrap.java b/test/app/utils/Bootstrap.java new file mode 100644 index 0000000..eaaf4d0 --- /dev/null +++ b/test/app/utils/Bootstrap.java @@ -0,0 +1,66 @@ +package utils; +import play.*; +import play.jobs.*; +import play.test.*; +import play.libs.Crypto; + +import models.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.*; + +import controllers.Photos; + +@OnApplicationStart +public class Bootstrap extends Job { + + public void doJob() throws FileNotFoundException, IOException{ + // Check if the database is empty + if(User.count() == 0) { + Fixtures.loadModels("default-data.yml");//Default User + //load in pictures + Photo photo; + String path = new java.io.File(".").getCanonicalPath() + "/public/images/"; + photo = Photos.initFileToPhoto(path+"GreenTaijitu.png", + "By Chinneeb via Wikimedia Commons"); + photo = Photos.initFileToPhoto(path+"default.png", + "Default Profile Photo"); + photo = Photos.initFileToPhoto(path + "headerBG.png", + "Default Header Background Photo"); + photo = Photos.initFileToPhoto(path + "UT-Austin-Tower.jpg", + "UT Austin via Wikimedia Commons"); + Fixtures.loadModels("skinTemplates.yml");//initial data for skin templates + Fixtures.loadModels("initial-data.yml");//rest of the data + hashPasswords(); + initFriends(); + } + } + + public static void hashPasswords() { + List users= User.findAll(); + for(User u : users) { + u.password = Crypto.passwordHash(u.password); + u.save(); + } + } + + public static void initFriends() { + List users = User.findAll(); + for (User u : users) { + u.friends.add(u); + u.save(); + } + User bob = User.findById(2L); + User alice = User.findById(3L); + User jeff = User.findById(4L); + + bob.friends.add(jeff); + alice.friends.add(jeff); + jeff.friends.add(bob); + jeff.friends.add(alice); + jeff.save(); + } + +} diff --git a/test/app/views/Answers/answer.html b/test/app/views/Answers/answer.html new file mode 100644 index 0000000..d606cf7 --- /dev/null +++ b/test/app/views/Answers/answer.html @@ -0,0 +1 @@ +#{answer currentUser:currentUser /} diff --git a/test/app/views/Application/about.html b/test/app/views/Application/about.html new file mode 100644 index 0000000..27e2326 --- /dev/null +++ b/test/app/views/Application/about.html @@ -0,0 +1,180 @@ +#{extends 'main.html' /} + + +   ${user.name} + +
    +
    +
    + About You + + + + + + + + + + #{if user.profile.bio} + + + + + #{/if} +
    Name${user.name}
    email${user.email}
    + ${user.profile.bio}
    +
    +
    + Information + + #{if user.profile.birthday} + + + + + #{/if} + #{if user.profile.gender} + + + + + #{/if} + + + + + + + + + + + + #{if user.profile.hasAnniversary()} + + + + + + #{/if} + + + + + + + + + + + + + +
    ${user.profile.birthday.format('MMM dd ')}
    ${user.profile.gender}
    + + #{select 'gender', value:user.profile.interestedIn} + #{option 'Male'}Male#{/option} + #{option 'Female'}Female#{/option} + #{option 'Both'}Both#{/option} + #{option 'Neither'}Neither#{/option} + #{/select} +
    + #{select 'status', value:user.profile.relationshipStatus} + #{option 'Single'}Single#{/option} + #{option 'In a relationship'}In a relationship#{/option} + #{option 'Engaged'}Engaged#{/option} + #{option 'Married'}Married#{/option} + #{option 'It\'s complicated'}It's complicated#{/option} + #{option 'In an open relationship'}In an open relationship#{/option} + #{option 'Widowed'}Widowed#{/option} + #{option 'Separated'}Separated#{/option} + #{option 'Divorced'}Divorced#{/option} + #{option 'In a civil union'}In a civil union#{/option} + #{option 'In a domestic partnership'}In a domestic partnership#{/option} + #{/select} +
    +
    + #{list items:user.profile.languages, as:'lang'} + ${lang.toString()} + #{/list} + +
    + +
    + +
    +
    +
    + Contact Info + + + + + + + + + +
    + +
    + +
    +
    +
    + +
    +
    + Work and Education + + + + + + + + + +
    + + #{list items:user.profile.education, as:'enrollment'} + ${enrollment.toString()} + #{/list} + +
    + #{list items:user.profile.work, as:'work'} + ${work.toString()} + #{/list} +
    +
    +
    + Living + + + + + +
    + +
    +
    +
    + Favorite Quotations + + + + + +
    + +
    +
    +
    +
    diff --git a/test/app/views/Application/account.html b/test/app/views/Application/account.html new file mode 100644 index 0000000..c33c7c2 --- /dev/null +++ b/test/app/views/Application/account.html @@ -0,0 +1,37 @@ +#{extends 'three_panel.html' /} +
    + + +

    Account Info

    +
    + + Change Skin + #{form @Application.account_save()} +
      +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    • +
    • #{ifErrors} +
        + #{errors} +
      • ${error}
      • #{/errors} +
      + #{/ifErrors} +
    + #{/form} +
    diff --git a/test/app/views/Application/group.html b/test/app/views/Application/group.html new file mode 100644 index 0000000..7e72906 --- /dev/null +++ b/test/app/views/Application/group.html @@ -0,0 +1,29 @@ +#{extends 'three_panel.html' /} + +
    + + + + + +
    [Picture]
    ${user.email}
    + news
    + Events
    + about
    + Checkin
    + friends:
    + #{list items:user.confirmedFriends(), as:'friendship'} + ${friendship.to.name }
    #{/list}
    Groups:
    + #{list items:user.getGroups(), as:'Group'} + ${Group.groupName}
    + #{/list} +
    +

    ${group.groupName}

    +

    ${group.description}

    +

    The group is owned by ${group.owner}

    +

    The Group members:

    + #{list items:group.members, as:'member'} + ${member.name}
    + #{/list} +
    +
    diff --git a/test/app/views/Application/list.html b/test/app/views/Application/list.html new file mode 100644 index 0000000..5cf7ab5 --- /dev/null +++ b/test/app/views/Application/list.html @@ -0,0 +1,18 @@ +#{extends 'CRUD/layout.html' /} #{set +title:messages.get('crud.list.title', type.name) /} + +
    + +

    &{'crud.list.title', type.name}

    + +
    #{crud.search /}
    + +
    #{crud.table /}
    + +
    #{crud.pagination /}
    + +

    + &{'crud.add', type.modelName} +

    + +
    \ No newline at end of file diff --git a/test/app/views/Application/news.html b/test/app/views/Application/news.html new file mode 100644 index 0000000..7970c00 --- /dev/null +++ b/test/app/views/Application/news.html @@ -0,0 +1,77 @@ +#{extends 'three_panel.html' /} +
    + + +
    + + +
    + + + + +
    + #{list items:user.news(), as:'item'} + #{post user:user,item:item /} + #{/list} +
    +
    + + + + + + diff --git a/test/app/views/Application/news.json b/test/app/views/Application/news.json new file mode 100644 index 0000000..8ecfe03 --- /dev/null +++ b/test/app/views/Application/news.json @@ -0,0 +1,10 @@ +[ + "users" : "/users", + "groups" : "/groups", + "events" : "/events", + "pages" : "/pages", + "posts" : "/posts", + "comments" : "/comments", + "photos" : "/photos", + "messages" : "/messages" +] \ No newline at end of file diff --git a/test/app/views/Application/profile.html b/test/app/views/Application/profile.html new file mode 100644 index 0000000..198bddd --- /dev/null +++ b/test/app/views/Application/profile.html @@ -0,0 +1,4 @@ +#{extends 'three_panel.html' /} + +
    + diff --git a/test/app/views/CRUD/layout.html b/test/app/views/CRUD/layout.html new file mode 100644 index 0000000..4f002fa --- /dev/null +++ b/test/app/views/CRUD/layout.html @@ -0,0 +1,40 @@ + + + + + #{get 'title' /} + + + + + + + + #{if request.actionMethod != 'index'} +
    + #{crud.navigation /} +
    + #{/if} + + #{if flash.success} +
    + ${flash.success} +
    + #{/if} + #{if flash.error || error} +
    + ${error ?: flash.error} +
    + #{/if} +
    + #{doLayout /} +
    + +
    + Generated by the Play CRUD module. Learn how to customize it ! +
    + + + diff --git a/test/app/views/Categories/listAll.html b/test/app/views/Categories/listAll.html new file mode 100644 index 0000000..2a89521 --- /dev/null +++ b/test/app/views/Categories/listAll.html @@ -0,0 +1,97 @@ +#{extends 'two_panel.html' /} #{set 'title'} OpenBook :: Forums #{/set} + +

    &{'thread.title'}

    + +
    + +
    + #{if Categories.size() < 8} &{'thread.createNewCategory'} + #{/if} &{'thread.deleteCategory'} +
    + +
    +
    +

    &{'thread.forum'}

    +
    +
    +

    &{'thread.lastPost'}

    +
    +
    + + #{if Categories.size()} #{list items:Categories, as:'category'} +
    +
    +

    + ${category.name} +

    + - ${category.description} +
    + #{if category.get_most_recent() != null} +
    + ${category.get_most_recent().title} +
    &{'thread.postedBy'}: + ${category.get_most_recent().owner}
    + ${category.get_most_recent().postedAt.format('M-d-yy, h:mm a')} +
    + #{/if} #{else} +
    &{'thread.none'}
    + #{/else} +
    + #{/list} #{/if} #{else} +
    &{'thread.nocategories'}
    + #{/else} + +
    + + + + + + + + + \ No newline at end of file diff --git a/test/app/views/Categories/listSingle.html b/test/app/views/Categories/listSingle.html new file mode 100644 index 0000000..f7d9ad7 --- /dev/null +++ b/test/app/views/Categories/listSingle.html @@ -0,0 +1,83 @@ +#{extends 'two_panel.html' /} #{set 'title'} OpenBook :: +${category.name} #{/set} + + +

    + &{'thread.title'} / ${category.name} +

    + +
    + + + +
    +
    +

    &{'thread.thread'}

    +
    +
    +

    &{'thread.lastPost'}

    +
    +
    + + #{if FThreads.size()} #{list items:FThreads, as:'FThread'} +
    +
    + #{if FThread.owner == _user} #{/if} +

    + ${FThread.title} +

    +
    + #{if FThread.comments().size() > 0} +
    + + ${FThread.last_comment().owner}
    + ${FThread.last_comment().createdAt.format('M-d-yy, h:mm a')} +
    + #{/if} #{else} +
    + ${FThread.owner}
    + ${FThread.postedAt.format('M-d-yy, h:mm a')} +
    + #{/else} +
    + #{/list} #{/if} #{else} +
    There are no threads in this + category.
    + #{/else} + +
    + + + + + diff --git a/test/app/views/Checkins/checkin.html b/test/app/views/Checkins/checkin.html new file mode 100644 index 0000000..45fce6e --- /dev/null +++ b/test/app/views/Checkins/checkin.html @@ -0,0 +1,24 @@ +#{extends 'two_panel.html' /} + +
    + +

    &{'checkin.checkin'}

    +
    + + + + + + +
    +

    &{'checkin.iamat'}...

    + +
    +
    + +
    diff --git a/test/app/views/Comments/addComment.html b/test/app/views/Comments/addComment.html new file mode 100644 index 0000000..d995879 --- /dev/null +++ b/test/app/views/Comments/addComment.html @@ -0,0 +1 @@ +#{comment user:user, comment:comment /} diff --git a/test/app/views/Comments/comment.html b/test/app/views/Comments/comment.html new file mode 100644 index 0000000..67c216b --- /dev/null +++ b/test/app/views/Comments/comment.html @@ -0,0 +1,3 @@ +#{extends 'two_panel.html' /} + +#{comment user:user, comment:comment /} diff --git a/test/app/views/Comments/comment.json b/test/app/views/Comments/comment.json new file mode 100644 index 0000000..89d91d2 --- /dev/null +++ b/test/app/views/Comments/comment.json @@ -0,0 +1,5 @@ +{ + "author" : "/users/${comment.owner.id}", + "content" : "${comment.content}", + "comment-on" : "/status/${comment.parentObj.id}" +} \ No newline at end of file diff --git a/test/app/views/Comments/comments.html b/test/app/views/Comments/comments.html new file mode 100644 index 0000000..bee8af5 --- /dev/null +++ b/test/app/views/Comments/comments.html @@ -0,0 +1,7 @@ +#{extends 'two_panel.html' /} + +
    + #{list comments, as:'comment'} + #{comment user:user, comment:comment /} + #{/list} +
    diff --git a/test/app/views/Comments/comments.json b/test/app/views/Comments/comments.json new file mode 100644 index 0000000..b3ed4b8 --- /dev/null +++ b/test/app/views/Comments/comments.json @@ -0,0 +1,5 @@ +[ + #{list items:comments, as:'item'} + "/comments/${item.id}"#{if !item_isLast},#{/if} + #{/list} +] \ No newline at end of file diff --git a/test/app/views/Events/addEvent.html b/test/app/views/Events/addEvent.html new file mode 100644 index 0000000..4f9cd0a --- /dev/null +++ b/test/app/views/Events/addEvent.html @@ -0,0 +1,281 @@ +#{extends 'two_panel.html' /} + +
    + + + + +

    Create Event

    +
    + #{form @Events.event_create()} + * = required +
      +
    • + + +
    • + +
    • + + +
    • + +
    • + + +
    • + +
    • +
    • + +
      + + + + + + + + + +
      +
    • + +
    • + +
      + + + + + + + + + + +
      +
    • +
    • + + +
    • +
    • + + + #{ifErrors} +
        + #{errors} +
      • ${error}
      • + #{/errors} +
      + #{/ifErrors} +
    • +
    + + + #{/form} +
    diff --git a/test/app/views/Events/event.html b/test/app/views/Events/event.html new file mode 100644 index 0000000..34bbc6f --- /dev/null +++ b/test/app/views/Events/event.html @@ -0,0 +1,111 @@ +#{extends 'two_panel.html' /} + + + + +
    +

    Event - ${event.name}

    +
    + + + + + + + +
    + Event Name: ${event.name}
    + ${privacy}
    + Created By: ${event.owner.name}
    + Date: ${dateString}
    + Location: ${event.location}
    + Details: ${event.script}
    +
    + +
    +
    + +

    Going(${event.getMemberCount()}):

    + #{list items:event.members, as:'member'} + ${member.name} + #{if user.equals(member) && !user.equals(event.owner)} + + Maybe + + + Not Going + + #{/if} +
    + #{/list} + + #{if event.getMaybeCount() > 0} +

    Maybe(${event.getMaybeCount()}):

    + #{list items:event.maybe, as:'mmember'} + ${mmember.name} + #{if user.equals(mmember) && !user.equals(event.owner)} + + Going + + + Not Going + + #{/if} +
    + #{/list} + #{/if} + + #{if event.getInvitedCount() > 0} +

    Invited(${event.getInvitedCount()}):

    + #{list items:event.awaitreply, as:'imember'} + ${imember.name} + #{if user.equals(imember) && !user.equals(event.owner)} + + Going + + + Maybe + + + Not Going + + #{/if} +
    + #{/list} + #{/if} +
    + + #{if event.uninvitedFriends(user).size() > 0} +

    Invite Friends:

    + #{list items:event.uninvitedFriends(user), as:'guest'} + ${guest.name} + + Invite + +
    + #{/list} + #{/if} +
    + + + #{form @Events.newEventPost(event.id,user.id)} + + + #{/form} + + +
    + #{list items:event.getPosts(), as:'item'} + #{post currentUser:currentUser,user:user,item:item /} + #{/list} +
    + Events +
    +
    +
    + diff --git a/test/app/views/Events/event.json b/test/app/views/Events/event.json new file mode 100644 index 0000000..9a17bb1 --- /dev/null +++ b/test/app/views/Events/event.json @@ -0,0 +1,12 @@ +{ + "name" : "${event.name}", + "location" : "${event.location}", + "details" : "${event.script}", + "owner" : "/users/${event.owner.id}", + "atendees" : + [ + #{list items:event.members, as:'user'} + "users/${user.id}"#{if !user_isLast},#{/if} + #{/list} + ] +} \ No newline at end of file diff --git a/test/app/views/Events/events.html b/test/app/views/Events/events.html new file mode 100644 index 0000000..b157973 --- /dev/null +++ b/test/app/views/Events/events.html @@ -0,0 +1,7 @@ +#{extends 'two_panel.html' /} +#{if user != null} + #{events currentUser:currentUser, events:events, today:today, title_string:"Upcoming Events", title2_string:"Today" /} +#{/if} +#{else} + #{events currentUser:currentUser, events:events, today:today, title_string:"All Events" /} +#{/else} \ No newline at end of file diff --git a/test/app/views/Events/events.json b/test/app/views/Events/events.json new file mode 100644 index 0000000..5b1e64b --- /dev/null +++ b/test/app/views/Events/events.json @@ -0,0 +1,8 @@ +[ + #{list items:events, as:'item'} + "/events/${item.id}"#{if !item_isLast},#{/if} + #{/list} + #{list items:today, as:'item2'} + "/events/${item2.id}"#{if !item2_isLast},#{/if} + #{/list} +] \ No newline at end of file diff --git a/test/app/views/Events/past.html b/test/app/views/Events/past.html new file mode 100644 index 0000000..ac728e5 --- /dev/null +++ b/test/app/views/Events/past.html @@ -0,0 +1,7 @@ +#{extends 'two_panel.html' /} +#{if user != null} + #{events currentUser:currentUser, events:events, today:today, title_string:"My Past Events" /} +#{/if} +#{else} + #{events currentUser:currentUser, events:events, today:today, title_string:"All Past Events" /} +#{/else} diff --git a/test/app/views/Events/upcoming.html b/test/app/views/Events/upcoming.html new file mode 100644 index 0000000..552e4ee --- /dev/null +++ b/test/app/views/Events/upcoming.html @@ -0,0 +1,7 @@ +#{extends 'two_panel.html' /} +#{if user != null} + #{events currentUser:currentUser, events:events, today:today, title_string:"Upcoming Events", title2_string:"Today" /} +#{/if} +#{else} + #{events currentUser:currentUser, events:events, today:today, title_string:"All Upcoming Events" /} +#{/else} diff --git a/test/app/views/FThreads/listSingle.html b/test/app/views/FThreads/listSingle.html new file mode 100644 index 0000000..4160566 --- /dev/null +++ b/test/app/views/FThreads/listSingle.html @@ -0,0 +1,59 @@ +#{extends 'two_panel.html' /} #{set 'title'} OpenBook :: ${thread.title} +#{/set} + + +

    + Public Threads / ${thread.category.name} / + ${thread.title} +

    + +
    + +
    +
    + + +

    + ${thread.owner} +

    + +
    +
    ${thread.content.nl2br()}
    +
    + + #{list items:thread.comments(), as:'comment'} +
    +
    + #{if comment.owner == _user} #{/if} + + +

    + ${comment.owner} +

    + +
    +
    ${comment.content.nl2br()}
    +
    + #{/list} + +
    +
    +
    +
    + + &{'thread.postReply'} +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/test/app/views/GroupSearch/index.html b/test/app/views/GroupSearch/index.html new file mode 100644 index 0000000..fbe17d4 --- /dev/null +++ b/test/app/views/GroupSearch/index.html @@ -0,0 +1,7 @@ +#{extends 'GroupSearch/layout.html' /} + +
    + +
    #{elasticSearch.search /}
    + +
    diff --git a/test/app/views/GroupSearch/layout.html b/test/app/views/GroupSearch/layout.html new file mode 100644 index 0000000..74326fa --- /dev/null +++ b/test/app/views/GroupSearch/layout.html @@ -0,0 +1,38 @@ + + + + +#{get 'title' /} + + + + + + + + #{if request.actionMethod != 'index'} +
    #{elasticSearch.navigation /}
    + #{/if} #{if flash.success} +
    ${flash.success}
    + #{/if} #{if flash.error || error} +
    ${error ?: + flash.error}
    + #{/if} + +
    #{doLayout /}
    + +
    + Generated by the Play! Elastic Search Module + by Felipe Oliveira. +
    + + + diff --git a/test/app/views/GroupSearch/list.html b/test/app/views/GroupSearch/list.html new file mode 100644 index 0000000..8fcff33 --- /dev/null +++ b/test/app/views/GroupSearch/list.html @@ -0,0 +1,18 @@ +#{extends 'CRUD/layout.html' /} #{set +title:messages.get('crud.list.title', type.name) /} + +
    + +

    HELLo

    + +
    #{crud.search /}
    + +
    #{crud.table /}
    + +
    #{crud.pagination /}
    + +

    + &{'crud.add', type.modelName} +

    + +
    diff --git a/test/app/views/GroupSearch/search.html b/test/app/views/GroupSearch/search.html new file mode 100644 index 0000000..16b1489 --- /dev/null +++ b/test/app/views/GroupSearch/search.html @@ -0,0 +1,15 @@ +#{extends 'main.html' /} + +
    + +

    Groups

    + Users |

    Groups

    +
    +
    + +
    #{GroupSearch.table /}
    + +
    #{elasticSearch.pagination + /}
    + +
    diff --git a/test/app/views/GroupSearch/show.html b/test/app/views/GroupSearch/show.html new file mode 100644 index 0000000..63b3edc --- /dev/null +++ b/test/app/views/GroupSearch/show.html @@ -0,0 +1,36 @@ +#{extends 'GroupSearch/layout.html' /} + +
    + +

    &{'elasticsearch.show.title', + type.modelName}

    + +
    + %{ currentObject = object currentType = + _('controllers.elasticsearch.ElasticSearchController$ObjectType').forClass(object.getClass().getName()) + + // Eval fields tags def fieldsHandler = [:] if(_body) { + _body.setProperty('fieldsHandler', fieldsHandler); _body.toString(); + // we skeep the real result ... } }% #{list items:_fields ?: + currentType.fields*.name, as:'fieldName'} %{ am = '' }% %{ def field = + currentType.getField(fieldName) }% + +
    %{ + if(fieldsHandler[fieldName]) { }% %{ def handler = + fieldsHandler[fieldName] handler.setProperty('fieldName', 'object.' + + field?.name + (field?.type == 'relation' ? '.' + currentType.keyName + : '')) def oldObject = handler.getProperty('object') + handler.setProperty('object', currentObject) + out.println(handler.toString()) handler.setProperty('object', + oldObject) handler.setProperty('fieldName', null) }% %{ } else { }% + + #{ifnot field} %{ throw new + play.exceptions.TagInternalException('Field not found -> ' + + fieldName) }% #{/ifnot} #{elasticsearch.textField name:field.name, + value:(currentObject ? currentObject[field.name] : null) /} %{ } }%
    + + #{/list} + +
    + +
    \ No newline at end of file diff --git a/test/app/views/Groups/group.html b/test/app/views/Groups/group.html new file mode 100644 index 0000000..e454b82 --- /dev/null +++ b/test/app/views/Groups/group.html @@ -0,0 +1,14 @@ +#{extends 'three_panel.html' /} +
    +

    ${group.groupName}

    +
    +

    ${group.description}

    +

    The group is owned by ${group.owner}

    +

    The Group members:

    + #{list items:group.members, as:'member'} + ${member.name} +
    + #{/list} +
    + #{include 'Groups/post.html' /} +
    diff --git a/test/app/views/Groups/post.html b/test/app/views/Groups/post.html new file mode 100644 index 0000000..50ba4b4 --- /dev/null +++ b/test/app/views/Groups/post.html @@ -0,0 +1,55 @@ +
    + + +
    + +
    + #{list items:group.getPosts(), as:'_item'} + #{include 'tags/post.html' /} + #{/list} +
    + diff --git a/test/app/views/Likeables/likes.json b/test/app/views/Likeables/likes.json new file mode 100644 index 0000000..8be25e3 --- /dev/null +++ b/test/app/views/Likeables/likes.json @@ -0,0 +1,5 @@ +[ + #{list items:thing.thoseWhoLike, as:'liker'} + "/users/${liker.id}"#{if !liker_isLast},#{/if} + #{/list} +] \ No newline at end of file diff --git a/test/app/views/Messages/createMessage.html b/test/app/views/Messages/createMessage.html new file mode 100644 index 0000000..95e00f3 --- /dev/null +++ b/test/app/views/Messages/createMessage.html @@ -0,0 +1,29 @@ +#{extends 'three_panel.html' /} + +
    + #{form @Messages.sendMessage()} +
      +
    • + + +
    • +
    • + + +
    • +
    • + +
    • + #{ifErrors} +
        + #{errors} +
      • ${error}
      • + #{/errors} +
      + #{/ifErrors} +
    + #{/form} +
    + + diff --git a/test/app/views/Messages/inbox.html b/test/app/views/Messages/inbox.html new file mode 100644 index 0000000..7aaa321 --- /dev/null +++ b/test/app/views/Messages/inbox.html @@ -0,0 +1,62 @@ +#{extends 'two_panel.html' /} + + +
    + +

    Inbox

    +
    +
    + Create Thread + +

    Messages

    +
    + #{list items:user.inbox(), as:'item'} + #{if item.getRecent() == null} +
    +
    +
    + + + +
    + + +
    + +
    + ${item.content.markdown().nl2br()} +
    + + See thread +
    +
    + #{/if} + + +
    +
    + #{/list} +
    +
    diff --git a/test/app/views/Messages/message.html b/test/app/views/Messages/message.html new file mode 100644 index 0000000..75a5f20 --- /dev/null +++ b/test/app/views/Messages/message.html @@ -0,0 +1,52 @@ +#{extends 'two_panel.html' /} + +
      +
    • + + +
      + ${item.content.markdown().nl2br()} +
      +
    • + + + + +
    • +
        + #{list items:item.getComments(), as:'comment'} +
      • #{comment user:user, comment:comment /}
      • + #{/list} +
      +
    • + +
    • + + + +
    • +
    + + + diff --git a/test/app/views/Notes/editNote.html b/test/app/views/Notes/editNote.html new file mode 100644 index 0000000..2cc496a --- /dev/null +++ b/test/app/views/Notes/editNote.html @@ -0,0 +1,32 @@ + + + + + + + Example + + +
    + Names: + + +
    + + + + + + diff --git a/test/app/views/Notes/newNote.html b/test/app/views/Notes/newNote.html new file mode 100644 index 0000000..f7e7971 --- /dev/null +++ b/test/app/views/Notes/newNote.html @@ -0,0 +1,19 @@ +#{extends 'two_panel.html' /} +#{form @Notes.saveNote()} +

    + + +

    +

    + + +

    +

    + +

    + #{ifErrors} +
      + #{errors}
    • ${error}
    • #{/errors} +
    + #{/ifErrors} +#{/form} \ No newline at end of file diff --git a/test/app/views/Notes/viewNotes.html b/test/app/views/Notes/viewNotes.html new file mode 100644 index 0000000..478f8e6 --- /dev/null +++ b/test/app/views/Notes/viewNotes.html @@ -0,0 +1,32 @@ +#{extends 'two_panel.html' /} + + + + +
    + +
    Create new note! + +

    Notes

    +
    + #{list items:user.viewNotes(), as:'item'} +
    +

    + ${item.title} +

    +
    +

    ${item.content.nl2br()}

    +
    +
    +
    + + #{/list} +
    + + diff --git a/test/app/views/Pages/admin.html b/test/app/views/Pages/admin.html new file mode 100644 index 0000000..233835e --- /dev/null +++ b/test/app/views/Pages/admin.html @@ -0,0 +1,52 @@ + + + + +
    + +
    +

    Update

    + #{form @Pages.pageUpdate(page.id, info)} + Admin: ${page.admin} + Delete this Page +
    Info: +
    +
    + +
    + #{/form} +
    + +
    +

    Upload Photo

    + #{ifErrors} +
      + #{errors} +
    • ${error}
    • + #{/errors} +
    + #{/ifErrors} + #{form @Pages.addPhoto(page.id), enctype:'multipart/form-data'} + + + #{/form} +
    + + #{if page.photos.size() > 0} +
    +

    All Photos

    + #{include 'Pages/pageBox.html' /} +
    + #{/if} +
    + + + + diff --git a/test/app/views/Pages/deletePage.html b/test/app/views/Pages/deletePage.html new file mode 100644 index 0000000..f672035 --- /dev/null +++ b/test/app/views/Pages/deletePage.html @@ -0,0 +1,3 @@ +#{extends 'main.html' /} +#{extends 'three_panel.html /} +
    Your page has succesfully been deleted!
    diff --git a/test/app/views/Pages/myPage.html b/test/app/views/Pages/myPage.html new file mode 100644 index 0000000..31108f8 --- /dev/null +++ b/test/app/views/Pages/myPage.html @@ -0,0 +1,57 @@ +#{extends 'main.html' /} +#{extends 'three_panel.html' /} + + +#{if page.admin == _user} + #{include 'Pages/admin.html' /} +#{/if} + #{include 'Pages/post.html' /} + + diff --git a/test/app/views/Pages/myPages.html b/test/app/views/Pages/myPages.html new file mode 100644 index 0000000..c081e75 --- /dev/null +++ b/test/app/views/Pages/myPages.html @@ -0,0 +1,35 @@ +#{extends 'main.html' /} #{extends 'three_panel.html' /} + +
    +

    Your Pages

    + #{if myPages.size > 0} +
    + Pages you are a fan off:
    + #{list items:myPages, as:'up'} + + + ${up.page.title} + + #{/list} +
    + #{/if} + #{if pages.size > 0} +
    + Pages you admin:
    + #{list items:pages, as:'_page'} + + + ${_page.title} + + #{/list} +
    +
    + #{/if} + #{else} + You have no pages + make one or + find one! + #{/else} +
    diff --git a/test/app/views/Pages/newPage.html b/test/app/views/Pages/newPage.html new file mode 100644 index 0000000..ce87d52 --- /dev/null +++ b/test/app/views/Pages/newPage.html @@ -0,0 +1,13 @@ +#{extends 'main.html' /} #{extends 'three_panel.html' /} +
    +
    Admin: ${currentUser.name} #{form @Pages.pageSave()} +
    + Title:
    Info:
    +
    +
    + #{/form} +
    +
    diff --git a/test/app/views/Pages/pageBox.html b/test/app/views/Pages/pageBox.html new file mode 100644 index 0000000..3197b06 --- /dev/null +++ b/test/app/views/Pages/pageBox.html @@ -0,0 +1,6 @@ +
    + Click picture to set as profile picture
    + #{list items:photos, as:'_photo'} + + #{/list} +
    diff --git a/test/app/views/Pages/pages.html b/test/app/views/Pages/pages.html new file mode 100644 index 0000000..d24a16f --- /dev/null +++ b/test/app/views/Pages/pages.html @@ -0,0 +1,20 @@ +#{extends 'three_panel.html' /} + + +
    + +

    Pages

    + Create a Page! +
    + +
    + #{list items:allPages, as:'pages'} + + + ${pages.title} + + #{/list} +
    + +
    diff --git a/test/app/views/Pages/photoBar.html b/test/app/views/Pages/photoBar.html new file mode 100644 index 0000000..fe5789a --- /dev/null +++ b/test/app/views/Pages/photoBar.html @@ -0,0 +1,22 @@ +
    + #{list items:photos, as:'_photo'} + + + + #{/list} +
    diff --git a/test/app/views/Pages/post.html b/test/app/views/Pages/post.html new file mode 100644 index 0000000..11a455d --- /dev/null +++ b/test/app/views/Pages/post.html @@ -0,0 +1,54 @@ + +
    + +
    + +
    + #{list items:page.getPosts(), as:'_item'} + #{include 'tags/post.html' /} + #{/list} +
    + diff --git a/test/app/views/Photos/photo.html b/test/app/views/Photos/photo.html new file mode 100644 index 0000000..1f51637 --- /dev/null +++ b/test/app/views/Photos/photo.html @@ -0,0 +1 @@ +#{photo currentUser:user, photo:photo /} diff --git a/test/app/views/Photos/photo.json b/test/app/views/Photos/photo.json new file mode 100644 index 0000000..88c4b4f --- /dev/null +++ b/test/app/views/Photos/photo.json @@ -0,0 +1,3 @@ +{ + "msg" : "photo info goes here" +} \ No newline at end of file diff --git a/test/app/views/Photos/photos.html b/test/app/views/Photos/photos.html new file mode 100644 index 0000000..79046e4 --- /dev/null +++ b/test/app/views/Photos/photos.html @@ -0,0 +1,35 @@ +#{extends 'three_panel.html' /} + + +
    + +

    Upload a new photo

    +
    + + #{ifErrors} +
      + #{errors} +
    • ${error}
    • + #{/errors} +
    + #{/ifErrors} + +
    + #{form @Photos.addPhoto(), enctype:'multipart/form-data'} + + + #{/form} +
    + +

    Your photos

    +
    + +
      + #{list items:photos, as:'photo'} + #{photo currentUser:currentUser, photo:photo /} + #{/list} +
    + +
    diff --git a/test/app/views/Photos/photos.json b/test/app/views/Photos/photos.json new file mode 100644 index 0000000..8aa8689 --- /dev/null +++ b/test/app/views/Photos/photos.json @@ -0,0 +1,5 @@ +[ + #{list items:photos, as:'item'} + "/photos/${item.id}"#{if !item_isLast},#{/if} + #{/list} +] \ No newline at end of file diff --git a/test/app/views/Photos/setProfilePhotoPage.html b/test/app/views/Photos/setProfilePhotoPage.html new file mode 100644 index 0000000..6287afe --- /dev/null +++ b/test/app/views/Photos/setProfilePhotoPage.html @@ -0,0 +1,43 @@ +#{extends 'three_panel.html' /} + +
    +

    &{'photo.setProfilePhoto'}

    +
    + + #{ifErrors} +
      + #{errors} +
    • ${error}
    • + #{/errors} +
    + #{/ifErrors} + + #{form @Photos.setGravatar(), method:'GET'} + Gravatar Email: + + #{/form} + + &{'photo.signUpGravatar'} +
    &{'photo.gravatarNote'}
    +
    + + + #{form @Photos.addProfilePhoto(), enctype:'multipart/form-data', method:'POST'} + &{'photo.newPhoto'}: + + + #{/form} +
    + &{'photo.useExistingPhoto'} +
    + + + +
    diff --git a/test/app/views/Posts/makeNewGroupPost.html b/test/app/views/Posts/makeNewGroupPost.html new file mode 100644 index 0000000..aba91ab --- /dev/null +++ b/test/app/views/Posts/makeNewGroupPost.html @@ -0,0 +1 @@ +#{post currentUser:currentUser,user:user,item:item /} diff --git a/test/app/views/Posts/makeNewPagePost.html b/test/app/views/Posts/makeNewPagePost.html new file mode 100644 index 0000000..aba91ab --- /dev/null +++ b/test/app/views/Posts/makeNewPagePost.html @@ -0,0 +1 @@ +#{post currentUser:currentUser,user:user,item:item /} diff --git a/test/app/views/Posts/makeNewPost.html b/test/app/views/Posts/makeNewPost.html new file mode 100644 index 0000000..c140eb5 --- /dev/null +++ b/test/app/views/Posts/makeNewPost.html @@ -0,0 +1 @@ +#{post user:user, item:post /} diff --git a/test/app/views/Posts/post.html b/test/app/views/Posts/post.html new file mode 100644 index 0000000..2155251 --- /dev/null +++ b/test/app/views/Posts/post.html @@ -0,0 +1,3 @@ +#{extends 'two_panel.html' /} + +#{post currentUser:currentUser,user:user,item:post /} diff --git a/test/app/views/Posts/post.json b/test/app/views/Posts/post.json new file mode 100644 index 0000000..a7b18b1 --- /dev/null +++ b/test/app/views/Posts/post.json @@ -0,0 +1,8 @@ +{ + "author" : "${post.owner.username}", + "parent" : "/postable/${post.postedObj.id}", + "visibility" : "${post.visibility.toString()}", + "content" : "${post.content}", + "creationdate" : "${post.createdAt}", + "updatedate": "${post.updatedAt}" +} diff --git a/test/app/views/Posts/posts.html b/test/app/views/Posts/posts.html new file mode 100644 index 0000000..2a27f37 --- /dev/null +++ b/test/app/views/Posts/posts.html @@ -0,0 +1,7 @@ +#{extends 'two_panel.html' /} + +
    + #{list items:posts, as:'item'} + #{post currentUser:currentUser,user:user,item:item /} + #{/list} +
    diff --git a/test/app/views/Posts/posts.json b/test/app/views/Posts/posts.json new file mode 100644 index 0000000..a9026df --- /dev/null +++ b/test/app/views/Posts/posts.json @@ -0,0 +1,5 @@ +[ + #{list items:posts, as:'item'} + "/posts/${item.id}"#{if !item_isLast},#{/if} + #{/list} +] \ No newline at end of file diff --git a/test/app/views/Questions/question.html b/test/app/views/Questions/question.html new file mode 100644 index 0000000..f476b17 --- /dev/null +++ b/test/app/views/Questions/question.html @@ -0,0 +1 @@ +#{question currentUser:currentUser, question:question /} diff --git a/test/app/views/Questions/questions.html b/test/app/views/Questions/questions.html new file mode 100644 index 0000000..e69de29 diff --git a/test/app/views/RSSFeeds/RSSfeeds.html b/test/app/views/RSSFeeds/RSSfeeds.html new file mode 100644 index 0000000..e46498b --- /dev/null +++ b/test/app/views/RSSFeeds/RSSfeeds.html @@ -0,0 +1,14 @@ + +#{list items:feeds, as:'feed'} + + + ${feed.getTitle()} + + + #{/list} \ No newline at end of file diff --git a/test/app/views/Secure/login.html b/test/app/views/Secure/login.html new file mode 100644 index 0000000..f5cc0e0 --- /dev/null +++ b/test/app/views/Secure/login.html @@ -0,0 +1,42 @@ +#{extends 'Secure/layout.html' /} + +
    + +

    &{'secure.title'}

    + + #{form @authenticate()} +
    + +
    +
    + #{if flash.error} +

    &{flash.error}

    + #{/if} #{if flash.success} +

    &{flash.success}

    + #{/if} + +

    + +

    +

    + +

    +

    + + +

    +

    + +

    +
    + Not a user? + Sign up! +
    +
    +
    + OpenBook 2012 + #{/form} +
    \ No newline at end of file diff --git a/test/app/views/Signup/signup.html b/test/app/views/Signup/signup.html new file mode 100644 index 0000000..8c9c4c1 --- /dev/null +++ b/test/app/views/Signup/signup.html @@ -0,0 +1,180 @@ + + + + + +
    +

    Sign up

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + +
    + +
    + +
    +
    +
    + + +
    + + + + + + + +
    + +
      + #{ifErrors} +
        + #{errors} +
      • ${error}
      • #{/errors} +
      #{/ifErrors}
    +
    + diff --git a/test/app/views/Skins/changeSkin.html b/test/app/views/Skins/changeSkin.html new file mode 100644 index 0000000..91054e3 --- /dev/null +++ b/test/app/views/Skins/changeSkin.html @@ -0,0 +1,14 @@ +#{extends 'two_panel.html' /} +
    +

    Skins

    +
    +
    + &{'skin.editMsg'} +
    +
    + #{list items: skinList, as:'skin'} + + #{/list} +
    diff --git a/test/app/views/Skins/editMySkin.html b/test/app/views/Skins/editMySkin.html new file mode 100644 index 0000000..2a36e26 --- /dev/null +++ b/test/app/views/Skins/editMySkin.html @@ -0,0 +1,242 @@ +#{extends 'two_panel.html' /} + +
    + ${makeSkinOutput} +
    + &{'skin.changeSkinMsg'} + + + #{form @Skins.editSkin()} +
    + + + +
    &{'skin.body'} + + + + +
    &{'skin.changeBGImageMsg'}
    +
    + + + +
    &{'skin.header'} + + + + + + +
    +
    +
    + + + +
    &{'skin.footer'} + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + + +
    &{'skin.section'} + + + + + + +
    +
    +
    + + + +
    &{'skin.label'} + + + + + + + + + + + +
    +
    +
    +
    + + + +
    &{'skin.comment'} + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + + +
    &{'skin.buttons'} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + +
    + #{ifErrors} +
      + #{errors}
    • ${error}
    • #{/errors} +
    + #{/ifErrors} +
    + #{/form} + + #{form @Skins.makeSkin()} +
    + + +
    + + + + + +
    +
    +
    + + + + + +
    +
    + #{/form} + +
    + diff --git a/test/app/views/Skins/sampleSkin.html b/test/app/views/Skins/sampleSkin.html new file mode 100644 index 0000000..c4ab6f9 --- /dev/null +++ b/test/app/views/Skins/sampleSkin.html @@ -0,0 +1,44 @@ + +
    +
    + &{'skin.openBook'} +
    + +
    +
    + &{'skin.thisIsTheSkin'}:
    ${skin.skinName}.
    + &{'skin.exampleTxt'} +

    + &{'skin.setSkinAsMySkin'} +
    + +
    diff --git a/test/app/views/Subscriptions/subscriptions.html b/test/app/views/Subscriptions/subscriptions.html new file mode 100644 index 0000000..b916fae --- /dev/null +++ b/test/app/views/Subscriptions/subscriptions.html @@ -0,0 +1,99 @@ +#{extends 'two_panel.html' /} + +
    + +

    Subscriptions:

    +
    +
    +
    +
    + On the List
    + #{list items:user.subscribedTo, as:'Subscribed'} + ${Subscribed.subscribed.name} +
    + #{/list} +
    + #{list items:user.subscriptionNews(), as:'item'} +
    +
    +
    + +
    +
    +
    ${item.content.markdown().nl2br()}
    + #{list items:item.getComments(), as:'comment'} +
    + +
    + ${comment.content.escape().nl2br()} +
    +
    + #{/list} + + -less
    +
    +
    + + +
    +
    +
    + #{/list} + + +
    + diff --git a/test/app/views/Timeline/Timeline.html b/test/app/views/Timeline/Timeline.html new file mode 100644 index 0000000..625cf73 --- /dev/null +++ b/test/app/views/Timeline/Timeline.html @@ -0,0 +1,85 @@ +#{extends 'three_panel.html' /} + +
    +

    ${user.first_name} ${user.last_name}

    + + + +
    +
    +

    + Name: ${user.first_name} ${user.last_name} +
    + Email: ${user.email} +
    + Username: ${user.username} +
    +

    +
    +
    +

    Some listing of interests!

    +
    +
    + + +
    + + + #{if !currentUser.equals(user)} +
    +
    + You and ${user.first_name} are friends. + +
    +
    + Ask to be friends with ${user.first_name}. + +
    +
    + × +

    ${user.first_name} wants to be friends with you.

    + + +
    +
    + You have asked ${user.first_name} to be friends. + +
    +
    + #{/if} + + +#{if user.timeline != null} +
    + #{list items:currentUser.timeline.getEvents(), as:'_item'} + #{include 'tags/post.html' /} + #{/list} +
    +#{/if} + +#{else} +#{if currentUser.equals(user)} +
    +

    Don't have Timeline?

    +
    + Get Timeline +
    +#{/if} +#{else} +
    +

    Looks like ${user.first_name} doesn't have timeline yet :(

    +
    +#{/else} +#{/else} + diff --git a/test/app/views/UpcomingBirthdays/showUpcomingBirthdays.html b/test/app/views/UpcomingBirthdays/showUpcomingBirthdays.html new file mode 100644 index 0000000..557c988 --- /dev/null +++ b/test/app/views/UpcomingBirthdays/showUpcomingBirthdays.html @@ -0,0 +1,34 @@ + + + +
    + #{if thisWeekBday.size()==0 && todayBday.size() == 0}There are no upcoming birthdays.#{/if} + #{else} + #{if todayBday.size() != 0} +
    Today:
    + + #{list items: todayBday, as:'birthdayPerson'} +

    + ${birthdayPerson} +
    + ${thisYear- birthdayPerson.getProfile().birthday.getYear()} years old +


    +

    + #{/list} + #{/if} + + + #{if thisWeekBday.size() != 0} +
    +
    This week:
    + #{list items: thisWeekBday, as:'birthdayPerson'} +

    + ${birthdayPerson} +
    + ${birthdayPerson.getProfile().birthday.format('MMM dd')} +


    +

    + #{/list} + #{/if} + #{/else} + diff --git a/test/app/views/UserSearch/index.html b/test/app/views/UserSearch/index.html new file mode 100644 index 0000000..248905c --- /dev/null +++ b/test/app/views/UserSearch/index.html @@ -0,0 +1,7 @@ +#{extends 'UserSearch/layout.html' /} + +
    + +
    #{elasticSearch.search /}
    + +
    diff --git a/test/app/views/UserSearch/layout.html b/test/app/views/UserSearch/layout.html new file mode 100644 index 0000000..74326fa --- /dev/null +++ b/test/app/views/UserSearch/layout.html @@ -0,0 +1,38 @@ + + + + +#{get 'title' /} + + + + + + + + #{if request.actionMethod != 'index'} +
    #{elasticSearch.navigation /}
    + #{/if} #{if flash.success} +
    ${flash.success}
    + #{/if} #{if flash.error || error} +
    ${error ?: + flash.error}
    + #{/if} + +
    #{doLayout /}
    + +
    + Generated by the Play! Elastic Search Module + by Felipe Oliveira. +
    + + + diff --git a/test/app/views/UserSearch/list.html b/test/app/views/UserSearch/list.html new file mode 100644 index 0000000..8fcff33 --- /dev/null +++ b/test/app/views/UserSearch/list.html @@ -0,0 +1,18 @@ +#{extends 'CRUD/layout.html' /} #{set +title:messages.get('crud.list.title', type.name) /} + +
    + +

    HELLo

    + +
    #{crud.search /}
    + +
    #{crud.table /}
    + +
    #{crud.pagination /}
    + +

    + &{'crud.add', type.modelName} +

    + +
    diff --git a/test/app/views/UserSearch/search.html b/test/app/views/UserSearch/search.html new file mode 100644 index 0000000..2680021 --- /dev/null +++ b/test/app/views/UserSearch/search.html @@ -0,0 +1,15 @@ +#{extends 'main.html' /} + +
    + +

    Users

    +

    Users

    | Groups +

    + + +
    #{UserSearch.table /}
    + +
    #{elasticSearch.pagination + /}
    + +
    diff --git a/test/app/views/UserSearch/show.html b/test/app/views/UserSearch/show.html new file mode 100644 index 0000000..bbc0b67 --- /dev/null +++ b/test/app/views/UserSearch/show.html @@ -0,0 +1,36 @@ +#{extends 'UserSearch/layout.html' /} + +
    + +

    &{'elasticsearch.show.title', + type.modelName}

    + +
    + %{ currentObject = object currentType = + _('controllers.elasticsearch.ElasticSearchController$ObjectType').forClass(object.getClass().getName()) + + // Eval fields tags def fieldsHandler = [:] if(_body) { + _body.setProperty('fieldsHandler', fieldsHandler); _body.toString(); + // we skeep the real result ... } }% #{list items:_fields ?: + currentType.fields*.name, as:'fieldName'} %{ am = '' }% %{ def field = + currentType.getField(fieldName) }% + +
    %{ + if(fieldsHandler[fieldName]) { }% %{ def handler = + fieldsHandler[fieldName] handler.setProperty('fieldName', 'object.' + + field?.name + (field?.type == 'relation' ? '.' + currentType.keyName + : '')) def oldObject = handler.getProperty('object') + handler.setProperty('object', currentObject) + out.println(handler.toString()) handler.setProperty('object', + oldObject) handler.setProperty('fieldName', null) }% %{ } else { }% + + #{ifnot field} %{ throw new + play.exceptions.TagInternalException('Field not found -> ' + + fieldName) }% #{/ifnot} #{elasticsearch.textField name:field.name, + value:(currentObject ? currentObject[field.name] : null) /} %{ } }%
    + + #{/list} + +
    + +
    \ No newline at end of file diff --git a/test/app/views/Users/friendRequests.html b/test/app/views/Users/friendRequests.html new file mode 100644 index 0000000..27586a2 --- /dev/null +++ b/test/app/views/Users/friendRequests.html @@ -0,0 +1,12 @@ +#{extends 'two_panel.html' /} + +
    + +

    Friend Requests

    + #{list items:user.friendRequests, as:'request'} + Accept + Deny + ${request.name}
    + #{/list} + +
    diff --git a/test/app/views/Users/friendRequests.json b/test/app/views/Users/friendRequests.json new file mode 100644 index 0000000..ca27e92 --- /dev/null +++ b/test/app/views/Users/friendRequests.json @@ -0,0 +1,5 @@ +[ + #{list items:user.friendRequests, as:'item'} + "/users/${item.id}"#{if !item_isLast},#{/if} + #{/list} +] diff --git a/test/app/views/Users/friends.html b/test/app/views/Users/friends.html new file mode 100644 index 0000000..b5fd70f --- /dev/null +++ b/test/app/views/Users/friends.html @@ -0,0 +1,44 @@ +#{extends 'two_panel.html' /} + +
    + +

    All Friends:

    +
    + +
    + + %{boolean toggle = true;}% + + #{list items:friends, as:'friendship'} + + #{if (toggle == true)} + + #{/if} + + #{else} + + #{/else} + + #{/list} +
    +
    + + ${friendship.name} +
    + +
    + %{toggle = false;}% +
    +
    +
    + + ${friendship.name} +
    + +
    + %{toggle = true;}% +
    +
    +
    diff --git a/test/app/views/Users/friends.json b/test/app/views/Users/friends.json new file mode 100644 index 0000000..cf210cc --- /dev/null +++ b/test/app/views/Users/friends.json @@ -0,0 +1,5 @@ +[ + #{list items:friends, as:'item'} + "/users/${item.id}"#{if !item_isLast},#{/if} + #{/list} +] diff --git a/test/app/views/Users/profile.html b/test/app/views/Users/profile.html new file mode 100644 index 0000000..95117ac --- /dev/null +++ b/test/app/views/Users/profile.html @@ -0,0 +1,353 @@ +#{extends 'main.html' /} + + + + +
    +
    +
    + #{ifErrors} + #{errors} +
  • ${error}
  • + #{/errors} + #{/ifErrors} + &{'profile.about.you'} +
    + +
    + + #{if profile.bio} + + + + + #{/if} +
    ${profile.bio}
    +
    +
    +
    + &{'profile.info'} +
    + +
    + + #{if profile.birthday != null} + + + + + #{/if} + #{if profile.gender} + + + + + #{/if} + #{if profile.interestedIn} + + + + + #{/if} + #{if profile.relationshipStatus} + + + + + #{/if} + #{if profile.anniversary != null} + + + + + #{/if} + #{if profile.languages.size() > 0} + + + + + #{/if} + #{if profile.religion} + + + + + #{/if} + #{if profile.political} + + + + + #{/if} +
    ${profile.birthday.format("MM/dd/yyyy")}
    ${profile.gender}
    ${profile.interestedIn}
    ${profile.relationshipStatus.toString()} +
    ${profile.anniversary.format("MM/dd/yyyy")}
    + #{list items:profile.languages, as:'lang'} + ${lang.toString()} + #{/list} + +
    ${profile.religion}
    ${profile.political}
    +
    +
    +
    + &{'profile.contact.info'} +
    + +
    + + #{if profile.phone} + + + + + #{/if} + #{if profile.address} + + + + + #{/if} +
    ${profile.phone}
    ${profile.address}
    +
    +
    +
    + +
    +
    + &{'profile.work.and.education'} +
    + +
    + + #{if profile.education.size() > 0} + + + + + #{/if} + #{if profile.work.size() > 0} + + + + + #{/if} +
    #{list items:profile.education, as:'enrollment'} + ${enrollment.toString()} #{/list} +
    #{list items:profile.work, as:'work'} + ${work.toString()} #{/list} +
    +
    +
    +
    + &{'profile.living'} +
    + +
    + + #{if profile.hometown} + + + + + #{/if} +
    ${profile.hometown.toString()}
    +
    +
    +
    + &{'profile.favorite.quotations'} +
    + +
    + + #{if profile.quotes} + + + + + #{/if} +
    ${profile.quotes}
    +
    +
    +
    +
    diff --git a/test/app/views/Users/user.html b/test/app/views/Users/user.html new file mode 100644 index 0000000..97d111a --- /dev/null +++ b/test/app/views/Users/user.html @@ -0,0 +1,49 @@ +#{extends 'main.html' /} +
    +
    + #{if (user.profile.profilePhoto.id == -1 || user.profile.profilePhoto == null)} + + #{/if} + #{else} + + #{/else} +
    + +
    + Born: ${ user.profile.birthday} +
    + Lives in: ${ user.profile.location} +
    +
    +
    + #{if !currentUser.equals(user)} +
    + You and ${user.first_name} are freinds. + +
    +
    + Ask to be freinds with ${user.first_name}. + +
    +
    + × +

    ${user.first_name} wants to be friends with you.

    + + +
    +
    + You have asked ${user.first_name} to be freinds. + +
    + #{/if} + #{list items:user.posts, as:'item'} + #{post user:currentUser, item:item /} + #{/list} +
    + + + diff --git a/test/app/views/Users/user.json b/test/app/views/Users/user.json new file mode 100644 index 0000000..cb91722 --- /dev/null +++ b/test/app/views/Users/user.json @@ -0,0 +1,17 @@ +{"user": + { + "username" : "${user.username}", + "first_name" : "${user.first_name}", + "middle_name" : "${user.middle_name}", + "last_name" : "${user.last_name}", + "posts" : "/users/${user.id}/posts", + "comments" : "/users/${user.id}/comments", + "events" : "/users/${user.id}/events", + "profile" : "/users/${user.id}/profile", + "timeline" : "/users/${user.id}/timeline", + "friends" : "/users/${user.id}/friends", + "friend-requests" : "/users/${user.id}/requests", + "likes" : "/users/${user.id}/likes", + "photos" : "/users/${user.id}/photos" + } +} \ No newline at end of file diff --git a/test/app/views/Users/users.html b/test/app/views/Users/users.html new file mode 100644 index 0000000..960b0cb --- /dev/null +++ b/test/app/views/Users/users.html @@ -0,0 +1,9 @@ +#{extends 'two_panel.html' /} + +
      + #{list items:users, as:'user'} +
    • + ${user} +
    • + #{/list} +
    diff --git a/test/app/views/Users/users.json b/test/app/views/Users/users.json new file mode 100644 index 0000000..b61132d --- /dev/null +++ b/test/app/views/Users/users.json @@ -0,0 +1,5 @@ +[ + #{list items:users, as:'item'} + "/users/${item.id}"#{if !item_isLast},#{/if} + #{/list} +] \ No newline at end of file diff --git a/test/app/views/errors/404.html b/test/app/views/errors/404.html new file mode 100644 index 0000000..cc79b8f --- /dev/null +++ b/test/app/views/errors/404.html @@ -0,0 +1,17 @@ + + + + + Not found + + + + #{if play.mode.name() == 'DEV'} + #{404 result /} + #{/if} + #{else} +

    Not found

    +

    ${result.message}

    + #{/else} + + diff --git a/test/app/views/errors/500.html b/test/app/views/errors/500.html new file mode 100644 index 0000000..d86d303 --- /dev/null +++ b/test/app/views/errors/500.html @@ -0,0 +1,19 @@ + + + + + Application error + + + + #{if play.mode.name() == 'DEV'} + #{500 exception /} + #{/if} + #{else} +

    Oops, an error occured

    + #{if exception instanceof play.exceptions.PlayException} +

    This exception has been logged with id ${exception.id}.

    + #{/if} + #{/else} + + diff --git a/test/app/views/main.html b/test/app/views/main.html new file mode 100644 index 0000000..9398648 --- /dev/null +++ b/test/app/views/main.html @@ -0,0 +1,118 @@ + + + + &{'title'} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + #{doLayout /} +
    +
    + is a + class project + to create a simple social networking web site +
    +
    + + diff --git a/test/app/views/tags/GroupSearch/table.html b/test/app/views/tags/GroupSearch/table.html new file mode 100644 index 0000000..f4453e8 --- /dev/null +++ b/test/app/views/tags/GroupSearch/table.html @@ -0,0 +1,64 @@ +%{ + // Eval fields tags + def fieldsHandler = [:] + if(_body) { + _body.setProperty('fieldsHandler', fieldsHandler); +}% + #{doBody as:'skip' /} +%{ + } +}% + + + + + + + + %{ _caller.objects.eachWithIndex() { object, k -> }% + + %{ if(_fields) { }% + %{ _fields.eachWithIndex() { field, i -> }% + + %{ } }% + %{ } else { }% + %{ if(fieldsHandler['default']) { }% + %{ + def handler = fieldsHandler['default']; + handler.setProperty('object', object); + }% + #{doBody body:handler /} + %{ } else { }% + + %{ } }% + %{ } }% + + %{ } }% +
    + %{ if(fieldsHandler[field]) { }% + %{ + def handler = fieldsHandler[field]; + handler.setProperty('object', object); + }% + #{doBody body:handler /} + %{ + handler.setProperty('object', null); + }% + %{ } else { }% + %{ if(i == 0) { }% + ${object[field]?.toString()?.escape()?.raw() ?: '(no value)'} + %{ } else { }% + %{ if(_caller.type.getField(field).type == 'file') { }% + %{ if(object[field]) { }% + ${object[field].filename} (${object[field].get().size().formatSize()}) + %{ } else { }% + + %{ } }% + %{ } else { }% + ${object[field]?.escape()?.raw()} + %{ } }% + %{ } }% + %{ } }% + + ${object.groupName ?: '(no value)'} +
    \ No newline at end of file diff --git a/test/app/views/tags/UserSearch/table.html b/test/app/views/tags/UserSearch/table.html new file mode 100644 index 0000000..a5a3c29 --- /dev/null +++ b/test/app/views/tags/UserSearch/table.html @@ -0,0 +1,64 @@ +%{ + // Eval fields tags + def fieldsHandler = [:] + if(_body) { + _body.setProperty('fieldsHandler', fieldsHandler); +}% + #{doBody as:'skip' /} +%{ + } +}% + + + + + + + + %{ _caller.objects.eachWithIndex() { object, k -> }% + + %{ if(_fields) { }% + %{ _fields.eachWithIndex() { field, i -> }% + + %{ } }% + %{ } else { }% + %{ if(fieldsHandler['default']) { }% + %{ + def handler = fieldsHandler['default']; + handler.setProperty('object', object); + }% + #{doBody body:handler /} + %{ } else { }% + + %{ } }% + %{ } }% + + %{ } }% +
    + %{ if(fieldsHandler[field]) { }% + %{ + def handler = fieldsHandler[field]; + handler.setProperty('object', object); + }% + #{doBody body:handler /} + %{ + handler.setProperty('object', null); + }% + %{ } else { }% + %{ if(i == 0) { }% + ${object[field]?.toString()?.escape()?.raw() ?: '(no value)'} + %{ } else { }% + %{ if(_caller.type.getField(field).type == 'file') { }% + %{ if(object[field]) { }% + ${object[field].filename} (${object[field].get().size().formatSize()}) + %{ } else { }% + + %{ } }% + %{ } else { }% + ${object[field]?.escape()?.raw()} + %{ } }% + %{ } }% + %{ } }% + + ${object.first_name + " " + object.last_name ?: '(no value)'} +
    diff --git a/test/app/views/tags/comment.html b/test/app/views/tags/comment.html new file mode 100644 index 0000000..e791d2a --- /dev/null +++ b/test/app/views/tags/comment.html @@ -0,0 +1,35 @@ +
    +
    + +
    +
    + + ${_comment.content.markdown().nl2br()} +
    +
    + +
    +
    diff --git a/test/app/views/tags/display.html b/test/app/views/tags/display.html new file mode 100644 index 0000000..3cb7e8c --- /dev/null +++ b/test/app/views/tags/display.html @@ -0,0 +1,45 @@ +*{ Display a post in one of these modes: 'full', 'home' or 'teaser' }* + +
    +

    + ${_post.title} +

    + + #{if _as != 'teaser'} +
    +
    Detail:
    + ${_post.content.markdown().nl2br()} +
    + #{/if} +
    + +#{if _as == 'full'} +
    +

    ${_post.comments().size() ?: 'no'} + COMMENT${_post.comments().size().pluralize()}

    + + #{list items:_post.comments(), as:'comment'} +
    + +
    + ${comment.content.escape().markdown().nl2br()}
    +
    + #{/list} +
    +#{/if} diff --git a/test/app/views/tags/events.html b/test/app/views/tags/events.html new file mode 100644 index 0000000..0f93595 --- /dev/null +++ b/test/app/views/tags/events.html @@ -0,0 +1,129 @@ +
    + + #{if _title_string.equals("Upcoming Events")} +

    Events

    + #{/if} + #{if _title_string.equals("My Past Events")} +

    Past Events

    + #{/if} + #{if _title_string.equals("Upcoming Declined Events")} +

    Declined Events

    + #{/if} + + +
    + + Create Event
    +
    +
    + + #{if _today.size() > 0} +

    ${_title2_string}

    + #{list items:_today, as:'todayevent'} + #{if todayevent.owner.equals(_currentUser)} + ${todayevent.name} + + Remove Event + +
    + #{/if} + #{else} + + #{if _title_string.equals("Upcoming Declined Events")} + #{if todayevent.declined.contains(_currentUser)} + ${todayevent.name} + + Join + + + Maybe + +
    + #{/if} + #{/if} + + #{else} + #{if todayevent.members.contains(_currentUser)} + ${todayevent.name} + You're going. +
    + #{/if} + #{if todayevent.maybe.contains(_currentUser)} + ${todayevent.name} + You might go. +
    + #{/if} + #{if todayevent.awaitreply.contains(_currentUser)} + ${todayevent.name} + + Join + + + Decline + +
    + #{/if} + #{/else} + + #{/else} + #{/list} +
    + #{/if} + + #{if _events.size() > 0} +

    ${_title_string}

    + #{list items:_events, as:'event'} + #{if event.owner.equals(_currentUser)} + ${event.name} + + Remove Event + +
    + #{/if} + #{else} + + #{if _title_string.equals("Upcoming Declined Events")} + #{if event.declined.contains(_currentUser)} + ${event.name} + + Join + + + Maybe + +
    + #{/if} + #{/if} + + #{else} + #{if event.members.contains(_currentUser)} + ${event.name} + You're going. +
    + #{/if} + #{if event.maybe.contains(_currentUser)} + ${event.name} + You might go. +
    + #{/if} + #{if event.awaitreply.contains(_currentUser)} + ${event.name} + + Join + + + Decline + +
    + #{/if} + #{/else} + + #{/else} + #{/list} + #{/if} + + #{if _title_string.equals("Upcoming Events")} +
    + Past Events
    + Declined Events + #{/if} +
    diff --git a/test/app/views/tags/lhsNav.html b/test/app/views/tags/lhsNav.html new file mode 100644 index 0000000..92f4319 --- /dev/null +++ b/test/app/views/tags/lhsNav.html @@ -0,0 +1,45 @@ + diff --git a/test/app/views/tags/photo.html b/test/app/views/tags/photo.html new file mode 100644 index 0000000..2e6fff1 --- /dev/null +++ b/test/app/views/tags/photo.html @@ -0,0 +1,14 @@ +
  • + + #{if _currentUser.equals(_photo.owner)} +
    + Delete picture +
    + &{'photo.setAsProfilePhoto'} +
    + Set as background + #{/if} +
  • diff --git a/test/app/views/tags/post.html b/test/app/views/tags/post.html new file mode 100644 index 0000000..2927e97 --- /dev/null +++ b/test/app/views/tags/post.html @@ -0,0 +1,78 @@ +
      +
    • + + +
      + #{if _item.getClass().getName() == "models.Photo"} +
      + +
      + #{/if} + #{elseif _item.getClass().getName() == "models.Link"} +
      + +
      + #{/elseif} + #{elseif _item.getClass().getName() == "models.Question"} +
      + #{question currentUser:currentUser, question:_item /} +
      + #{/elseif} + #{else} + ${_item.content.markdown().nl2br()} + #{/else} +
      +
    • + + + + +
    • +
        + #{list items:_item.getComments(), as:'comment'} +
      • #{comment user:_user, comment:comment /}
      • + #{/list} +
      +
    • + +
    • + + + +
    • +
    + + diff --git a/test/app/views/tags/question.html b/test/app/views/tags/question.html new file mode 100644 index 0000000..363606a --- /dev/null +++ b/test/app/views/tags/question.html @@ -0,0 +1,11 @@ +
    + ${_question.content}
    +
      + %{ + _question.answers.each{println "
    • "+it.answer+" : "+it.numTimesAnswered()+"
    • "} + }% +
    + +
    diff --git a/test/app/views/tags/rhsNav.html b/test/app/views/tags/rhsNav.html new file mode 100644 index 0000000..db175a5 --- /dev/null +++ b/test/app/views/tags/rhsNav.html @@ -0,0 +1,58 @@ + + + + + + + + diff --git a/test/app/views/tags/timeago.html b/test/app/views/tags/timeago.html new file mode 100644 index 0000000..138b953 --- /dev/null +++ b/test/app/views/tags/timeago.html @@ -0,0 +1,4 @@ +%{ String iso8601 = "yyyy-MM-dd'T'HH:mmZ"; }% + + ${_date.format()} + diff --git a/test/app/views/three_panel.html b/test/app/views/three_panel.html new file mode 100644 index 0000000..66688fb --- /dev/null +++ b/test/app/views/three_panel.html @@ -0,0 +1,4 @@ +#{extends 'main.html' /} +
    #{lhsNav user:currentUser /}
    +
    #{doLayout /}
    +
    #{rhsNav user:currentUser /}
    diff --git a/test/app/views/two_panel.html b/test/app/views/two_panel.html new file mode 100644 index 0000000..f13c4c5 --- /dev/null +++ b/test/app/views/two_panel.html @@ -0,0 +1,4 @@ +#{extends 'main.html' /} +
    #{lhsNav user:currentUser /}
    +
    #{doLayout /}
    + diff --git a/test/conf/application.conf b/test/conf/application.conf new file mode 100644 index 0000000..7a7990b --- /dev/null +++ b/test/conf/application.conf @@ -0,0 +1,221 @@ +# This is the main configuration file for the application. +# ~~~~~ +application.name=OpenBook + +# Application mode +# ~~~~~ +# Set to dev to enable instant reloading and other development help. +# Otherwise set to prod. +application.mode=dev + +# Change this to the hosted server when it is created +application.baseUrl=http://localhost:9000 +%prod.application.mode=prod + +# Secret key +# ~~~~~ +# The secret key is used to secure cryptographics functions +# If you deploy your application to several instances be sure to use the same key ! +application.secret=y86O6T9aWvPhUdyuYlpO267c57AdmK7Ozsx10S7C3U76M5NW643z9DpG2q3IS7Fr + +# i18n +# ~~~~~ +# Define locales used by your application. +# You can then place localized messages in conf/messages.{locale} files +# application.langs=fr,en,ja + +# Date format +# ~~~~~ +date.format=MMM d, yyyy +# date.format.fr=dd/MM/yyyy + +# Server configuration +# ~~~~~ +# If you need to change the HTTP port, uncomment this (default is set to 9000) +# http.port=9000 +# +# By default the server listen for HTTP on the wilcard address. +# You can restrict this. +# http.address=127.0.0.1 +# +# Use this if you don't host your Play application at the root of the domain +# you're serving it from. This parameter has no effect when deployed as a +# war, because the path will be handled by the application server. +# http.path=/ + +# Session configuration +# ~~~~~~~~~~~~~~~~~~~~~~ +# By default, session will be written to the transient PLAY_SESSION cookie. +# The cookies are not secured by default, only set it to true +# if you're serving your pages through https. +# application.session.cookie=PLAY +# application.session.maxAge=1h +# application.session.secure=false + +# Session/Cookie sharing between subdomain +# ~~~~~~~~~~~~~~~~~~~~~~ +# By default a cookie is only valid for a specific domain. By setting +# application.defaultCookieDomain to '.example.com', the cookies +# will be valid for all domains ending with '.example.com', ie: +# foo.example.com and bar.example.com +# application.defaultCookieDomain=.example.com + +# JVM configuration +# ~~~~~ +# Define which port is used by JPDA when application is in debug mode (default is set to 8000) +# jpda.port=8000 +# +# Java source level => 1.5, 1.6 or 1.7 (experimental) +# java.source=1.5 + +# Log level +# ~~~~~ +# Specify log level for your application. +# If you want a very customized log, create a log4j.properties file in the conf directory +# application.log=INFO +# +# More logging configuration +# application.log.path=/log4j.properties +# application.log.system.out=off + +# Database configuration +# ~~~~~ +# Enable a database engine if needed. +# +# To quickly set up a development database, use either: +# - mem : for a transient in memory database (H2 in memory) +# - fs : for a simple file written database (H2 file stored) +db=mem +# +# To connect to a local MySQL5 database, use: +# db=mysql://root@localhost/openbook +# +# To connect to a local PostgreSQL9 database, use: +# db=postgres://user:pwd@host/database +# +# If you need a full JDBC configuration use the following : +# db.url=jdbc:postgresql:database_name +# db.driver=org.postgresql.Driver +# db.user=root +# db.pass=secret +# +# Connections pool configuration : +# db.pool.timeout=1000 +# db.pool.maxSize=30 +# db.pool.minSize=10 +# +# If you want to reuse an existing Datasource from your application server, use: +# db=java:/comp/env/jdbc/myDatasource +# +# When using an existing Datasource, it's sometimes needed to destroy it when +# the application is stopped. Depending on the datasource, you can define a +# generic "destroy" method : +# db.destroyMethod=close + +# JPA Configuration (Hibernate) +# ~~~~~ +# +# Specify the custom JPA dialect to use here (default to guess): +# jpa.dialect=org.hibernate.dialect.PostgreSQLDialect +# +# Specify the ddl generation pattern to use. Set to none to disable it +# (default to update in DEV mode, and none in PROD mode): +# jpa.ddl=update +# +# Debug SQL statements (logged using DEBUG level): +# jpa.debugSQL=true +# +# You can even specify additional hibernate properties here: +# hibernate.use_sql_comments=true +# ... +# +# Store path for Blob content +attachments.path=data/attachments + +# Memcached configuration +# ~~~~~ +# Enable memcached if needed. Otherwise a local cache is used. +# memcached=enabled +# +# Specify memcached host (default to 127.0.0.1:11211) +# memcached.host=127.0.0.1:11211 +# +# Or you can specify multiple host to build a distributed cache +# memcached.1.host=127.0.0.1:11211 +# memcached.2.host=127.0.0.1:11212 +# +# Use plain SASL to authenticate for memcached +# memcached.user= +# memcached.password= + +# HTTP Response headers control for static files +# ~~~~~ +# Set the default max-age, telling the user's browser how long it should cache the page. +# Default is 3600 (one hour). Set it to 0 to send no-cache. +# This is only read in prod mode, in dev mode the cache is disabled. +# http.cacheControl=3600 + +# If enabled, Play will generate entity tags automatically and send a 304 when needed. +# Default is true, set it to false to deactivate use of entity tags. +# http.useETag=true + +# Custom mime types +# mimetype.xpi=application/x-xpinstall + +# WS configuration +# ~~~~~ +# Default engine is Async Http Client, uncomment to use +# the JDK's internal implementation +# webservice = urlfetch +# If you need to set proxy params for WS requests +# http.proxyHost = localhost +# http.proxyPort = 3128 +# http.proxyUser = jojo +# http.proxyPassword = jojo + +# Mail configuration +# ~~~~~ +# Default is to use a mock Mailer +# mail.smtp=mock + +# Or, specify mail host configuration +mail.smtp.host=smtp.gmail.com +mail.smtp.user=openbooksignup@gmail.com +mail.smtp.channel=ssl + +# Url-resolving in Jobs +# ~~~~~~ +# When rendering templates with reverse-url-resoling (@@{..}) in Jobs (which do not have an inbound Http.Request), +# ie if sending a HtmlMail, Play need to know which url your users use when accessing your app. +# %test.application.baseUrl=http://localhost:9000/ +# %prod.application.baseUrl=http://www.yourdomain.com/ + +# Jobs executor +# ~~~~~~ +# Size of the Jobs pool +# play.jobs.pool=10 + +# Execution pool +# ~~~~~ +# Default to 1 thread in DEV mode or (nb processors + 1) threads in PROD mode. +# Try to keep a low as possible. 1 thread will serialize all requests (very useful for debugging purpose) +# play.pool=3 + +# Open file from errors pages +# ~~~~~ +# If your text editor supports opening files by URL, Play! will +# dynamically link error pages to files +# +# Example, for textmate: +# play.editor=txmt://open?url=file://%s&line=%s + +# ElasticSearch configuration +elasticsearch.local=false + +# Testing. Set up a custom configuration for test mode +# ~~~~~ +#%test.module.cobertura=${play.path}/modules/cobertura +%test.application.mode=dev +%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0 +%test.jpa.ddl=create +%test.mail.smtp=mock diff --git a/test/conf/data.yml b/test/conf/data.yml new file mode 100644 index 0000000..b9f7572 --- /dev/null +++ b/test/conf/data.yml @@ -0,0 +1,2 @@ +# Generated by logisima-play-yml (http://github.com/sim51/logisima-play-yml). +# This module is a part of LogiSima (http://www.logisima.com). diff --git a/test/conf/default-data.yml b/test/conf/default-data.yml new file mode 100644 index 0000000..0db9c88 --- /dev/null +++ b/test/conf/default-data.yml @@ -0,0 +1,9 @@ +# Default data +User(default): + first_name: default + last_name: user + name: default user + username: default + email: default@example.com + password: secret + isAdmin: false diff --git a/test/conf/dependencies.yml b/test/conf/dependencies.yml new file mode 100644 index 0000000..c68d7c1 --- /dev/null +++ b/test/conf/dependencies.yml @@ -0,0 +1,24 @@ +# Application dependencies + +require: + - play -> secure + - play -> crud + - play -> logisimayml 1.8 + - play -> elasticsearch 0.3 + - play -> markdown 1.7 + - org.elasticsearch -> elasticsearch 0.17 + - se.scalablesolutions.akka -> akka-amqp 1.1.2 + - net.coobird -> thumbnailator 0.4.1 + +repositories: + - elasticsearch: + type: iBiblio + root: "http://oss.sonatype.org/content/repositories/releases/" + contains: + - org.elasticsearch -> * + + - akka: + type: iBiblio + root: "http://repo.akka.io/releases/" + contains: + - se.scalablesolutions.akka -> * diff --git a/test/conf/initial-data.yml b/test/conf/initial-data.yml new file mode 100644 index 0000000..366fa03 --- /dev/null +++ b/test/conf/initial-data.yml @@ -0,0 +1,266 @@ +# Test data + +User(bob): + first_name: Bob + last_name: Thomson + name: Bob Thomson + username: b3bob + email: bob@gmail.com + password: secret + isAdmin: true + subscription: true + + +User(alice): + first_name: Alice + last_name: Xu + name: Alice Xu + username: axu + email: alice@gmail.com + password: secret + #significant_other: jeff + anniversary: 2010-12-2 + subscription: true + +User(jeff): + first_name: Jeff + last_name: Jones + username: jj99 + name: Jeff Jones + email: jeff@gmail.com + password: secret + significant_other: alice + anniversary: 2010-12-2 + +User(gparker): + first_name: Geoffrey + last_name: Parker + username: gparker + name: Geoffrey Parker + email: grp@gparker.com + password: password + isAdmin: true + subscription: true + +Profile(bobProfile): + owner: bob + gender: male + locale: Austin + significantOther: alice + anniversary: 2000-01-01 + birthday: 1990-04-29 + phone: 555-123-4567 + address: 123 Somewhere St. + email: bob@gmail.com + bio: > + Hi, I'm Bob + religion: Jewish + +Profile(jeffProfile): + owner: jeff + birthday: 1992-05-05 + +Profile(aliceProfile): + owner: alice + birthday: 1991-05-10 + +Profile(gparkerProfile): + owner: gparker + +Status(firstBobStatus): + owner: bob + visibility: FRIENDS + content: > + Short sweet twitter like messages that will have inline @mentions and #tags. + +Status(firstJeffStatus): + owner: jeff + visibility: FRIENDS + content: > + Hey @b3bob hope you like #MassEffect3 + +Status(secondBobStatus): + owner: bob + visibility: FRIENDS + content: > + @jj99 It is the most amazing game ever! 5 out of 5! #MassEffect3 + +Post(firstBobPost): + postedObj: bob + date: 2009-06-14 + owner: bob + visibility: PUBLIC + content: > + The model has a central position in a Play! application. It is the domain-specific + representation of the information on which the application operates. + + Martin fowler defines it as: + + Responsible for representing concepts of the business, information about the + business situation, and business rules. State that reflects the business situation + is controlled and used here, even though the technical details of storing it are + delegated to the infrastructure. This layer is the heart of business software. + +Post(secondBobPost): + postedObj: bob + date: 2009-03-25 + owner: bob + visibility: FRIENDS + content: > + Well, it's just a test. + +Post(jeffPost): + postedObj: jeff + date: 2009-06-06 + owner: jeff + visibility: FRIENDS + content: > + A Play! application follows the MVC architectural pattern as applied to the + architecture of the Web. + + This pattern splits the application into separate layers: the Presentation + layer and the Model layer. The Presentation layer is further split into a + View and a Controller layer. + +Post(jeffPost2): + postedObj: jeff + date: 2009-06-07 + owner: jeff + visibility: FRIENDS + content: > + More stuff + +Group(g1): + owner: bob + groupName: Bob's cool group + members: [bob,jeff] + description: > + A group for cool people to talk about cool things in a cool place. + +Group(g2): + owner: alice + groupName: Alice's first group + members: [alice] + description: > + This is a description for Alice's group. + +Post(g1 post1): + postedObj: g1 + date: 2009-06-07 + owner: bob + visibility: FRIENDS + content: > + This is the first post for Bob's group. It shouldn't appear on his news feed! + +Post(g1 post2): + postedObj: g1 + date: 2009-06-07 + owner: jeff + visibility: FRIENDS + content: > + And this is a second post. + +Post(g2 post1): + postedObj: g2 + date: 2009-06-07 + owner: alice + visibility: FRIENDS + content: > + First post! + +Profile(jeffP): + User: jeff + gender: male + phone: 555-888-1234 + website: www.jeffisawesome.com + quotes: qwertyyuiop + bio: > + Hi, my name is Jeff, I have a really cool bio. Stay tuned for more + +Page(cats): + admin: alice + title: CATS + profilePhoto: 2 + info: > + I haz them!! + +Page(nachoCheese): + admin: jeff + title: Nacho Cheese + profilePhoto: 2 + info: > + What do you call cheese that isn't yours? + +Post(cats post1): + postedObj: cats + date: 2009-06-07 + owner: bob + visibility: FRIENDS + content: > + I HATE CATZ!!! + +Post(cats post2): + postedObj: cats + date: 2009-06-07 + owner: jeff + visibility: FRIENDS + content: > + CHEEZEBURGAHZ!! + +Post(nachoCheese post1): + postedObj: nachoCheese + date: 2009-06-07 + owner: jeff + visibility: FRIENDS + content: > + Nobody likes my page :( + +UserPage(nachoCheese jeff): + fan: jeff + page: cats + +Subscription(sub1): + subscribed: alice + subscriber: bob + +Subscription(sub2): + subscribed: gparker + subscriber: bob + +Subscription(sub3): + subscribed: gparker + subscriber: alice + +Subscription(sub4): + subscribed: bob + subscriber: alice + +RSSFeed(feed1): + subscriber: bob + url: http://www.nytimes.com/services/xml/rss/nyt/Business.xml + is_valid: true + +RSSFeed(feed2): + subscriber: alice + url: http://www.nytimes.com/services/xml/rss/nyt/Science.xml + is_valid: true + +RSSFeed(feed3): + subscriber: jeff + url: http://www.nytimes.com/services/xml/rss/nyt/Sports.xml + is_valid: true + +RSSFeed(feed4): + subscriber: bob + url: http://rss.cnn.com/rss/edition.rss + is_valid: true + +RSSFeed(feed5): + subscriber: alice + url: http://rss.cnn.com/rss/edition_world.rss + is_valid: true + +RSSFeed(feed6): + subscriber: jeff + url: http://rss.cnn.com/rss/edition_space.rss + is_valid: true diff --git a/test/conf/messages b/test/conf/messages new file mode 100644 index 0000000..09f68a6 --- /dev/null +++ b/test/conf/messages @@ -0,0 +1,112 @@ +# You can specialize this file for each language. +# For example, for French create a messages.fr file +# +validation.image.type=You must specify a valid image type to upload +validation.match=Invalid image format +# "%2$d" returns the second parameter of the max() method in decimal form. +validation.max=Image size cannot exceed %2$d bytes + +#Universal +accept=Accept +cancel=Cancel + +# Title +title=openbook + +# Checkin +checkin.at=You checked in at +checkin.checkin=Checkin +checkin.iamat=I am at +checkin.checkedinat=Checked in at: + + +# Comment +comment.like = Like +comment.unlike = Unlike +comment.delete = delete + +# Profile +profile.about.you=About You +profile.bio=Bio +profile.info=Information +profile.birthday=Birthday +profile.sex=Sex +profile.interested.in=Interested In +profile.relationship.status=Relationship Status +profile.anniversary=Anniversary +profile.languages=Languages +profile.religious.views=Religious Views +profile.political.views=Political Views +profile.contact.info=Contact Info +profile.phone=Phone +profile.address=Address +profile.work.and.education=Work and Education +profile.education=Education +profile.work.history=Work History +profile.living=Living +profile.hometown=Hometown +profile.favorite.quotations=Favorite Quotations +profile.quote=Quotes +validation.phone=Please enter a phone number +validation.match=Please enter a valid date format (MM/dd/yyyy) + +# Skin +skin.editMsg=Edit My Skin +skin.changeSkinMsg=Change Skin to Template +skin.editCurrentSkinMsg=EDIT CURRENT SKIN +skin.body=Body +skin.changeBGImageMsg=Choose Background Image +skin.header=Header +skin.bgColor=Background Color +skin.footer=Footer +skin.txtAlign=Text Alignment +skin.fontSize=Font Size +skin.color=Color +skin.section=Section +skin.label=Label +skin.comment=Comment +skin.borderSize=Border Size +skin.borderColor=Border Color +skin.buttons=Buttons +skin.borderRadius=Border Radius +skin.borderBoxShadowColor=Border Box Shadow Color +skin.txtDec=Text Decoration (underline,etc) +skin.unvisitedLinkColor=Unvisited Link Color +skin.visitedLinkColor=Visited Link Color +skin.hoverLinkColor=Link Hover Color +skin.selectedLinkColor=Selected Link Color +skin.save=Save +skin.makeNewSkinMsg=MAKE NEW PUBLIC SKIN (Visible to Everyone) +skin.skinName=SkinName +skin.openBook=OpenBook +skin.thisIsTheSkin=This is the Skin +skin.exampleTxt=This is example text. +skin.setSkinAsMySkin=Set Skin as My Skin + +#Photos +photo.useExistingPhoto=Use Existing Photo +photo.currentProfilePhoto=Current Profile Photo +photo.newPhoto=New Photo +photo.upload=Upload +photo.setProfilePhoto=Set Your Profile Photo +photo.setAsProfilePhoto=Set as Profile Photo +photo.useGravatar="Use Gravatar" +photo.signUpGravatar=Sign up to use Gravatar +photo.gravatarNote=Note: After signing up, it may take some time for the photo to propagate. +photo.notFound=That photo does not exist. + +#Threads +thread.title=Public Threads +thread.forum=Forum +thread.lastPost=Last post +thread.postedBy=Posted by +thread.createNewCategory=Create Category +thread.deleteCategory=Delete Category +thread.createNewThread=Create Thread +thread.thread=Thread +thread.name=Name +thread.description=Description +thread.threadTitle=Title +thread.none=None +thread.nocategories=There are no thread categories currently configured. Click the button above to create some. +thread.postReply=Post Reply diff --git a/test/conf/routes b/test/conf/routes new file mode 100644 index 0000000..678cee9 --- /dev/null +++ b/test/conf/routes @@ -0,0 +1,159 @@ +# Routes +# This file defines all application routes (Higher priority routes first) +# ~~~~ + +# Import Secure routes +* / module:secure + +GET /es-admin elasticsearch.ElasticSearchAdmin.index +GET /es-admin/ elasticsearch.ElasticSearchAdmin.index + +# Home page +GET / Application.news + + + +#Account +GET /users/? Users.users #Get a list of all users +POST /users/? Signup.signup_user +PUT /users/{<[0-9]+>userId} Users.updateUser +GET /users/{<[0-9]+>userId} Users.user #Get account info for a specific user +DELETE /users/{<[0-9]+>userId} Users.deleteUser #Delete a user +GET /users/{<[0-9]+>userId}/profile Users.profile +GET /users/{<[0-9]+>userId}/friends Users.friends +POST /users/{<[0-9]+>userId}/friends Users.requestFriends +DELETE /users/{<[0-9]+>userId}/friends Users.removeFriends +GET /users/{<[0-9]+>userId}/requests Users.friendRequests +GET /users/{<[0-9]+>ownerId}/photos/? Photos.photos +GET /users/{<[0-9]+>userId}/posts/? Posts.posts #get all posts by a user +GET /users/{<[0-9]+>userId}/comments/? Comments.userComments #get all comments by a user +GET /users/{<[0-9]+>userId}/events/? Events.events #1 user's events + +GET /testFriends Users.testFriends + + +#Skins +GET /public/stylesheets/main.css Skins.stylesheet +GET /changeSkin Skins.changeSkin +GET /editMySkin Skins.editMySkin +GET /sampleSkin Skins.sampleSkin +GET /changeBGImage Photos.changeBGImage +POST /skins/changeSkinToTemplate Skins.changeSkinToTemplate +POST /skins/editSkin Skins.editSkin +POST /skins/setBackgroundPhoto Skins.setBackgroundPhoto + +# Threads +GET /threads Categories.listAll +GET /threads/{<[0-9]+>catId} Categories.listSingle +GET /threads/[0-9]+/{<[0-9]+>threadId} FThreads.listSingle +POST /threads/newCategory Categories.newCategory +POST /threads/deleteCategory Categories.deleteCategory +POST /threads/newThread FThreads.newThread +POST /threads/deleteThread FThreads.deleteThread + + +# Profile +GET /application.prev.gif staticFile:/public/images/prev.gif +GET /application.next.gif staticFile:/public/images/next.gif +GET /application.calendar.jpg staticFile:/public/images/calendar.gif + +# Photos +GET /photos/? Photos.photos +POST /photos Photos.addPhoto +GET /photos/{<[0-9]+>photoId} Photos.getPhoto +GET /photos/setProfilePhoto Photos.setProfilePhoto +POST /photos/setProfilePhoto Photos.setProfilePhoto +GET /photos/{<[0-9]+>photoId}/delete Photos.removePhoto +GET /photos/setProfilePhotoPage Photos.setProfilePhotoPage +POST /photos/setProfilePhoto Photos.setProfilePhoto +POST /photos/addProfilePhoto Photos.addProfilePhoto +GET /photos/setGravatar Photos.setGravatar + +# Profile Pic Editor +GET /profilePicEditor Photos.setProfilePhotoPage + +# Thumbnails +GET /photos/120x120/{<[0-9]+>photoId} Thumbnails.get120x120 +GET /photos/50x50/{<[0-9]+>photoId} Thumbnails.get50x50 +GET /photos/30x30/{<[0-9]+>photoId} Thumbnails.get30x30 + +#Signup +GET /signup Signup.signup +GET /captcha Signup.captcha + +# Messages +GET /messages Messages.inbox +GET /messages/createMessage Messages.createMessage +POST /messages Messages.sendMessage +GET /messages/{<[0-9]+>messageId} Messages.message + +# Notes +GET /notes Notes.viewNotes +GET /notes/newNote Notes.newNote +POST /notes Notes.saveNote + +# Search +GET /users/search UserSearch.search +GET /groups/search GroupSearch.search + +#Posts +GET /posts/? Posts.posts #Get all posts +POST /posts/? Posts.makeNewPost +GET /posts/{<[0-9]+>postId} Posts.post #Get a specific post +DELETE /posts/{<[0-9]+>postId} Posts.deletePost #Delete a post + +#Links +#Post /links/? #Add/update link + +#Questions +POST /questions Questions.askQuestion +GET /answers/{<[0-9]+>answerId} Answers.chooseAnswer + +#Comments +GET /comments/? Comments.comments #Get all comments +GET /comments/{<[0-9]+>commentId} Comments.comment #Get a specific comment +DELETE /comments/{<[0-9]+>commentId} Comments.deleteComment #Delete a comment +GET /{Commentable}/{<[0-9]+>statusId}/comments/? Comments.comments #Get all comments for a status +POST /{Commentable}/{<[0-9]+>statusId}/comments/? Comments.addComment #Add a comment to a status + +#Events +GET /events/? Events.events #all events +GET /events/upcoming/? Events.upcoming #upcoming events +GET /events/past/? Events.past #past events +GET /users/{<[0-9]+>userId}/events/upcoming/? Events.upcoming #1 users upcoming events +GET /users/{<[0-9]+>userId}/events/past/? Events.past #1 users past events +GET /events/{<[0-9]+>eventId} Events.event #1 event + +GET /events/eventcreator Events.addEvent +POST /events Events.addEvent + +#Relationships +GET /relationships Relationships.relationships + +#Timeline +GET /users/{<[0-9]+>userId}/timeline Timeline.Timeline #Get timeline for specific user + +# Checkin +GET /checkins Checkins.checkin +GET /checkins/at Checkins.at + +* /photos/{anything} 404 +* /users/{anything}/photos/? 404 + +# Groups +GET /groups/{id} Groups.group + +#Likes +GET /{Likeable}/{<[0-9]+>likeableId}/likes Likeables.likes +POST /{Likeable}/{<[0-9]+>likeableId}/likes Likeables.like +DELETE /{Likeable}/{<[0-9]+>likeableId}/likes Likeables.unLike + + +# Ignore favicon requests +GET /favicon.ico 404 + +# Map static resources from the /app/public folder to the /public path +GET /public/ staticDir:public + +# Catch all +* /{controller}/{action} {controller}.{action} diff --git a/test/conf/skinTemplates.yml b/test/conf/skinTemplates.yml new file mode 100644 index 0000000..431e5b6 --- /dev/null +++ b/test/conf/skinTemplates.yml @@ -0,0 +1,479 @@ +#Set of templates for the Skins + +#Green Skin (greenHeader) +models.Skin(GREEN): + userName: default + skinName: green + name: defaultgreen + isPublic: "true" + +models.SkinPair(models_SkinPair_1): + attachedSkin: GREEN + name: bodyBGPhoto + value: none + +models.SkinPair(models_SkinPair_a_1): + attachedSkin: GREEN + name: bodyBGColor + value: none + +models.SkinPair(models_SkinPair_2): + attachedSkin: GREEN + name: headerBGPhoto + value: none + +models.SkinPair(models_SkinPair_5): + attachedSkin: GREEN + name: headerBGColor + value: 148203 + +models.SkinPair(models_SkinPair_6): + attachedSkin: GREEN + name: footerTextAlign + value: center + +models.SkinPair(models_SkinPair_7): + attachedSkin: GREEN + name: footerFontSize + value: 10 + +models.SkinPair(models_SkinPair_8): + attachedSkin: GREEN + name: footerColor + value: 858A7B + +models.SkinPair(models_SkinPair_9): + attachedSkin: GREEN + name: sectionAlign + value: top + +models.SkinPair(models_SkinPair_10): + attachedSkin: GREEN + name: labelFontSize + value: 10 + +models.SkinPair(models_SkinPair_11): + attachedSkin: GREEN + name: labelColor + value: 148203 + +models.SkinPair(models_SkinPair_12): + attachedSkin: GREEN + name: commentBorderSize + value: 2 + +models.SkinPair(models_SkinPair_13): + attachedSkin: GREEN + name: commentBorderColor + value: 000000 + +models.SkinPair(models_SkinPair_14): + attachedSkin: GREEN + name: commentBGColor + value: EEEEEE + +models.SkinPair(models_SkinPair_15): + attachedSkin: GREEN + name: buttonBorderRadius + value: 4 + +models.SkinPair(models_SkinPair_16): + attachedSkin: GREEN + name: buttonBorderSize + value: 1 + +models.SkinPair(models_SkinPair_17): + attachedSkin: GREEN + name: buttonBorderColor + value: 000000 + +models.SkinPair(models_SkinPair_18): + attachedSkin: GREEN + name: buttonBoxShadowColor + value: 008000 + +models.SkinPair(models_SkinPair_19): + attachedSkin: GREEN + name: buttonBGColor + value: FFFFFF + +models.SkinPair(models_SkinPair_20): + attachedSkin: GREEN + name: buttonTextDec + value: none + +models.SkinPair(models_SkinPair_21): + attachedSkin: GREEN + name: buttonLinkUnvisitedColor + value: 000000 + +models.SkinPair(models_SkinPair_22): + attachedSkin: GREEN + name: buttonLinkVisitedColor + value: 148203 + +models.SkinPair(models_SkinPair_23): + attachedSkin: GREEN + name: buttonLinkHoverColor + value: 008000 + +models.SkinPair(models_SkinPair_24): + attachedSkin: GREEN + name: buttonLinkSelectedColor + value: 000000 + + +#Peace Skin +models.Skin(peace): + userName: default + skinName: peace + name: defaultpeace + isPublic: "true" + +models.SkinPair(models_SkinPair_26): + attachedSkin: peace + name: bodyBGPhoto + value: /photos/1 + +models.SkinPair(models_SkinPair_a_2): + attachedSkin: peace + name: bodyBGColor + value: none + +models.SkinPair(models_SkinPair_27): + attachedSkin: peace + name: headerBGPhoto + value: none + +models.SkinPair(models_SkinPair_30): + attachedSkin: peace + name: headerBGColor + value: 148203 + +models.SkinPair(models_SkinPair_31): + attachedSkin: peace + name: footerTextAlign + value: center + +models.SkinPair(models_SkinPair_32): + attachedSkin: peace + name: footerFontSize + value: 10 + +models.SkinPair(models_SkinPair_33): + attachedSkin: peace + name: footerColor + value: 858A7B + +models.SkinPair(models_SkinPair_34): + attachedSkin: peace + name: sectionAlign + value: top + +models.SkinPair(models_SkinPair_35): + attachedSkin: peace + name: labelFontSize + value: 10 + +models.SkinPair(models_SkinPair_36): + attachedSkin: peace + name: labelColor + value: 000000 + +models.SkinPair(models_SkinPair_37): + attachedSkin: peace + name: commentBorderSize + value: 2 + +models.SkinPair(models_SkinPair_38): + attachedSkin: peace + name: commentBorderColor + value: black + +models.SkinPair(models_SkinPair_39): + attachedSkin: peace + name: commentBGColor + value: EEEEEE + +models.SkinPair(models_SkinPair_40): + attachedSkin: peace + name: buttonBorderRadius + value: 4 + +models.SkinPair(models_SkinPair_41): + attachedSkin: peace + name: buttonBorderSize + value: 1 + +models.SkinPair(models_SkinPair_42): + attachedSkin: peace + name: buttonBorderColor + value: black + +models.SkinPair(models_SkinPair_43): + attachedSkin: peace + name: buttonBoxShadowColor + value: 008000 + +models.SkinPair(models_SkinPair_44): + attachedSkin: peace + name: buttonBGColor + value: FFFFFF + +models.SkinPair(models_SkinPair_45): + attachedSkin: peace + name: buttonTextDec + value: none + +models.SkinPair(models_SkinPair_46): + attachedSkin: peace + name: buttonLinkUnvisitedColor + value: black + +models.SkinPair(models_SkinPair_47): + attachedSkin: peace + name: buttonLinkVisitedColor + value: 48203 + +models.SkinPair(models_SkinPair_48): + attachedSkin: peace + name: buttonLinkHoverColor + value: 008000 + +models.SkinPair(models_SkinPair_49): + attachedSkin: peace + name: buttonLinkSelectedColor + value: black + + +#Default Skin (orange header) +models.Skin(default_skin): + userName: default + skinName: default_skin + name: defaultdefault_skin + name: default_skin + isPublic: "true" + +models.SkinPair(models_SkinPair_50): + attachedSkin: default_skin + name: bodyBGPhoto + value: none + +models.SkinPair(models_SkinPair_54): + attachedSkin: default_skin + name: headerBGPhoto + value: /photos/3 + + +models.SkinPair(models_SkinPair_55): + attachedSkin: default_skin + name: footerTextAlign + value: center + +models.SkinPair(models_SkinPair_56): + attachedSkin: default_skin + name: footerFontSize + value: 10 + +models.SkinPair(models_SkinPair_57): + attachedSkin: default_skin + name: footerColor + value: 858A7B + +models.SkinPair(models_SkinPair_58): + attachedSkin: default_skin + name: sectionAlign + value: top + +models.SkinPair(models_SkinPair_59): + attachedSkin: default_skin + name: labelFontSize + value: 10 + +models.SkinPair(models_SkinPair_60): + attachedSkin: default_skin + name: labelColor + value: 000000 + +models.SkinPair(models_SkinPair_61): + attachedSkin: default_skin + name: commentBorderSize + value: 2 + +models.SkinPair(models_SkinPair_62): + attachedSkin: default_skin + name: commentBorderColor + value: 000000 + +models.SkinPair(models_SkinPair_63): + attachedSkin: default_skin + name: commentBGColor + value: EEEEEE + +models.SkinPair(models_SkinPair_64): + attachedSkin: default_skin + name: buttonBorderRadius + value: 4 + +models.SkinPair(models_SkinPair_65): + attachedSkin: default_skin + name: buttonBorderSize + value: 1 + +models.SkinPair(models_SkinPair_66): + attachedSkin: default_skin + name: buttonBorderColor + value: 000000 + +models.SkinPair(models_SkinPair_67): + attachedSkin: default_skin + name: buttonBoxShadowColor + value: 888888 + +models.SkinPair(models_SkinPair_68): + attachedSkin: default_skin + name: buttonBGColor + value: FFFFFF + +models.SkinPair(models_SkinPair_69): + attachedSkin: default_skin + name: buttonTextDec + value: none + +models.SkinPair(models_SkinPair_70): + attachedSkin: default_skin + name: buttonLinkUnvisitedColor + value: 000000 + +models.SkinPair(models_SkinPair_71): + attachedSkin: default_skin + name: buttonLinkVisitedColor + value: 000000 + +models.SkinPair(models_SkinPair_72): + attachedSkin: default_skin + name: buttonLinkHoverColor + value: E0E0FF + +models.SkinPair(models_SkinPair_73): + attachedSkin: default_skin + name: buttonLinkSelectedColor + value: 000000 + + +#UT Skin +models.Skin(ut_skin): + userName: default + skinName: ut_skin + name: defaultut_skin + isPublic: "true" + +models.SkinPair(models_SkinPair_74): + attachedSkin: ut_skin + name: bodyBGPhoto + value: /photos/4 + +models.SkinPair(models_SkinPair_75): + attachedSkin: ut_skin + name: headerBGPhoto + value: /photos/3 + +models.SkinPair(models_SkinPair_75_2): + attachedSkin: ut_skin + name: headerBGColor + value: none + +models.SkinPair(models_SkinPair_76): + attachedSkin: ut_skin + name: footerTextAlign + value: center + +models.SkinPair(models_SkinPair_77): + attachedSkin: ut_skin + name: footerFontSize + value: 10 + +models.SkinPair(models_SkinPair_78): + attachedSkin: ut_skin + name: footerColor + value: 858A7B + +models.SkinPair(models_SkinPair_79): + attachedSkin: ut_skin + name: sectionAlign + value: top + +models.SkinPair(models_SkinPair_80): + attachedSkin: ut_skin + name: labelFontSize + value: 10 + +models.SkinPair(models_SkinPair_81): + attachedSkin: ut_skin + name: labelColor + value: 000000 + +models.SkinPair(models_SkinPair_82): + attachedSkin: ut_skin + name: commentBorderSize + value: 2 + +models.SkinPair(models_SkinPair_83): + attachedSkin: ut_skin + name: commentBorderColor + value: 000000 + +models.SkinPair(models_SkinPair_84): + attachedSkin: ut_skin + name: commentBGColor + value: EEEEEE + +models.SkinPair(models_SkinPair_85): + attachedSkin: ut_skin + name: buttonBorderRadius + value: 4 + +models.SkinPair(models_SkinPair_86): + attachedSkin: ut_skin + name: buttonBorderSize + value: 1 + +models.SkinPair(models_SkinPair_87): + attachedSkin: ut_skin + name: buttonBorderColor + value: 000000 + +models.SkinPair(models_SkinPair_88): + attachedSkin: ut_skin + name: buttonBoxShadowColor + value: 888888 + +models.SkinPair(models_SkinPair_89): + attachedSkin: ut_skin + name: buttonBGColor + value: FFFFFF + +models.SkinPair(models_SkinPair_90): + attachedSkin: ut_skin + name: buttonTextDec + value: none + +models.SkinPair(models_SkinPair_91): + attachedSkin: ut_skin + name: buttonLinkUnvisitedColor + value: 000000 + +models.SkinPair(models_SkinPair_92): + attachedSkin: ut_skin + name: buttonLinkVisitedColor + value: 000000 + +models.SkinPair(models_SkinPair_93): + attachedSkin: ut_skin + name: buttonLinkHoverColor + value: E0E0FF + +models.SkinPair(models_SkinPair_94): + attachedSkin: ut_skin + name: buttonLinkSelectedColor + value: 000000 \ No newline at end of file diff --git a/modules/elasticsearch-0.3/app/controllers/elasticsearch/ElasticSearchController.java b/test/modules/elasticsearch-0.3/app/controllers/elasticsearch/ElasticSearchController.java similarity index 100% rename from modules/elasticsearch-0.3/app/controllers/elasticsearch/ElasticSearchController.java rename to test/modules/elasticsearch-0.3/app/controllers/elasticsearch/ElasticSearchController.java diff --git a/test/public/bootstrap/.gitignore b/test/public/bootstrap/.gitignore new file mode 100644 index 0000000..2b1ffbf --- /dev/null +++ b/test/public/bootstrap/.gitignore @@ -0,0 +1,36 @@ +# Numerous always-ignore extensions +*.diff +*.err +*.orig +*.log +*.rej +*.swo +*.swp +*.zip +*.vi +*~ +*.sass-cache + +# OS or Editor folders +.DS_Store +._* +Thumbs.db +.cache +.project +.settings +.tmproj +*.esproj +nbproject +*.sublime-project +*.sublime-workspace + +# Komodo +*.komodoproject +.komodotools + +# Folders to ignore +.hg +.svn +.CVS +.idea +node_modules diff --git a/test/public/bootstrap/.travis.yml b/test/public/bootstrap/.travis.yml new file mode 100644 index 0000000..b8e1f17 --- /dev/null +++ b/test/public/bootstrap/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - 0.6 \ No newline at end of file diff --git a/public/bootstrap/docs/build/node_modules/hogan.js/LICENSE b/test/public/bootstrap/LICENSE similarity index 99% rename from public/bootstrap/docs/build/node_modules/hogan.js/LICENSE rename to test/public/bootstrap/LICENSE index 4947287..2bb9ad2 100644 --- a/public/bootstrap/docs/build/node_modules/hogan.js/LICENSE +++ b/test/public/bootstrap/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/test/public/bootstrap/Makefile b/test/public/bootstrap/Makefile new file mode 100644 index 0000000..827b692 --- /dev/null +++ b/test/public/bootstrap/Makefile @@ -0,0 +1,94 @@ +BOOTSTRAP = ./docs/assets/css/bootstrap.css +BOOTSTRAP_LESS = ./less/bootstrap.less +BOOTSTRAP_RESPONSIVE = ./docs/assets/css/bootstrap-responsive.css +BOOTSTRAP_RESPONSIVE_LESS = ./less/responsive.less +DATE=$(shell date +%I:%M%p) +CHECK=\033[32m✔\033[39m +HR=\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\# + + +# +# BUILD DOCS +# + +build: + @echo "\n${HR}" + @echo "Building Bootstrap..." + @echo "${HR}\n" + @jshint js/*.js --config js/.jshintrc + @jshint js/tests/unit/*.js --config js/.jshintrc + @echo "Running JSHint on javascript... ${CHECK} Done" + @recess --compile ${BOOTSTRAP_LESS} > ${BOOTSTRAP} + @recess --compile ${BOOTSTRAP_RESPONSIVE_LESS} > ${BOOTSTRAP_RESPONSIVE} + @echo "Compiling LESS with Recess... ${CHECK} Done" + @node docs/build + @cp img/* docs/assets/img/ + @cp js/*.js docs/assets/js/ + @cp js/tests/vendor/jquery.js docs/assets/js/ + @echo "Compiling documentation... ${CHECK} Done" + @cat js/bootstrap-transition.js js/bootstrap-alert.js js/bootstrap-button.js js/bootstrap-carousel.js js/bootstrap-collapse.js js/bootstrap-dropdown.js js/bootstrap-modal.js js/bootstrap-tooltip.js js/bootstrap-popover.js js/bootstrap-scrollspy.js js/bootstrap-tab.js js/bootstrap-typeahead.js > docs/assets/js/bootstrap.js + @uglifyjs -nc docs/assets/js/bootstrap.js > docs/assets/js/bootstrap.min.tmp.js + @echo "/**\n* Bootstrap.js by @fat & @mdo\n* Copyright 2012 Twitter, Inc.\n* http://www.apache.org/licenses/LICENSE-2.0.txt\n*/" > docs/assets/js/copyright.js + @cat docs/assets/js/copyright.js docs/assets/js/bootstrap.min.tmp.js > docs/assets/js/bootstrap.min.js + @rm docs/assets/js/copyright.js docs/assets/js/bootstrap.min.tmp.js + @echo "Compiling and minifying javascript... ${CHECK} Done" + @echo "\n${HR}" + @echo "Bootstrap successfully built at ${DATE}." + @echo "${HR}\n" + @echo "Thanks for using Bootstrap," + @echo "<3 @mdo and @fat\n" + +# +# RUN JSHINT & QUNIT TESTS IN PHANTOMJS +# + +test: + jshint js/*.js --config js/.jshintrc + jshint js/tests/unit/*.js --config js/.jshintrc + node js/tests/server.js & + phantomjs js/tests/phantom.js "http://localhost:3000/js/tests" + kill -9 `cat js/tests/pid.txt` + rm js/tests/pid.txt + +# +# BUILD SIMPLE BOOTSTRAP DIRECTORY +# recess & uglifyjs are required +# + +bootstrap: + mkdir -p bootstrap/img + mkdir -p bootstrap/css + mkdir -p bootstrap/js + cp img/* bootstrap/img/ + recess --compile ${BOOTSTRAP_LESS} > bootstrap/css/bootstrap.css + recess --compress ${BOOTSTRAP_LESS} > bootstrap/css/bootstrap.min.css + recess --compile ${BOOTSTRAP_RESPONSIVE_LESS} > bootstrap/css/bootstrap-responsive.css + recess --compress ${BOOTSTRAP_RESPONSIVE_LESS} > bootstrap/css/bootstrap-responsive.min.css + cat js/bootstrap-transition.js js/bootstrap-alert.js js/bootstrap-button.js js/bootstrap-carousel.js js/bootstrap-collapse.js js/bootstrap-dropdown.js js/bootstrap-modal.js js/bootstrap-tooltip.js js/bootstrap-popover.js js/bootstrap-scrollspy.js js/bootstrap-tab.js js/bootstrap-typeahead.js > bootstrap/js/bootstrap.js + uglifyjs -nc bootstrap/js/bootstrap.js > bootstrap/js/bootstrap.min.tmp.js + echo "/*!\n* Bootstrap.js by @fat & @mdo\n* Copyright 2012 Twitter, Inc.\n* http://www.apache.org/licenses/LICENSE-2.0.txt\n*/" > bootstrap/js/copyright.js + cat bootstrap/js/copyright.js bootstrap/js/bootstrap.min.tmp.js > bootstrap/js/bootstrap.min.js + rm bootstrap/js/copyright.js bootstrap/js/bootstrap.min.tmp.js + +# +# MAKE FOR GH-PAGES 4 FAT & MDO ONLY (O_O ) +# + +gh-pages: bootstrap docs + rm -f docs/assets/bootstrap.zip + zip -r docs/assets/bootstrap.zip bootstrap + rm -r bootstrap + rm -f ../bootstrap-gh-pages/assets/bootstrap.zip + node docs/build production + cp -r docs/* ../bootstrap-gh-pages + +# +# WATCH LESS FILES +# + +watch: + echo "Watching less files..."; \ + watchr -e "watch('less/.*\.less') { system 'make' }" + + +.PHONY: docs watch gh-pages \ No newline at end of file diff --git a/test/public/bootstrap/README.md b/test/public/bootstrap/README.md new file mode 100644 index 0000000..54ea405 --- /dev/null +++ b/test/public/bootstrap/README.md @@ -0,0 +1,132 @@ +[Twitter Bootstrap](http://twitter.github.com/bootstrap) [![Build Status](https://secure.travis-ci.org/twitter/bootstrap.png)](http://travis-ci.org/twitter/bootstrap) +================= + +Bootstrap provides simple and flexible HTML, CSS, and Javascript for popular user interface components and interactions. In other words, it's a front-end toolkit for faster, more beautiful web development. It's created and maintained by [Mark Otto](http://twitter.com/mdo) and [Jacob Thornton](http://twitter.com/fat) at Twitter. + +To get started, checkout http://twitter.github.com/bootstrap! + + + +Quick start +----------- + +Clone the repo, `git clone git@github.com:twitter/bootstrap.git`, or [download the latest release](https://github.com/twitter/bootstrap/zipball/master). + + + +Versioning +---------- + +For transparency and insight into our release cycle, and for striving to maintain backward compatibility, Bootstrap will be maintained under the Semantic Versioning guidelines as much as possible. + +Releases will be numbered with the follow format: + +`..` + +And constructed with the following guidelines: + +* Breaking backward compatibility bumps the major (and resets the minor and patch) +* New additions without breaking backward compatibility bumps the minor (and resets the patch) +* Bug fixes and misc changes bumps the patch + +For more information on SemVer, please visit http://semver.org/. + + + +Bug tracker +----------- + +Have a bug? Please create an issue here on GitHub! + +https://github.com/twitter/bootstrap/issues + + + +Twitter account +--------------- + +Keep up to date on announcements and more by following Bootstrap on Twitter, [@TwBootstrap](http://twitter.com/TwBootstrap). + + + +Blog +---- + +Read more detailed announcements, discussions, and more on [The Official Twitter Bootstrap Blog](http://blog.getbootstrap.com). + + + +Mailing list +------------ + +Have a question? Ask on our mailing list! + +twitter-bootstrap@googlegroups.com + +http://groups.google.com/group/twitter-bootstrap + + + +IRC +--- + +Server: irc.freenode.net + +Channel: ##twitter-bootstrap (the double ## is not a typo) + + + +Developers +---------- + +We have included a makefile with convenience methods for working with the Bootstrap library. + ++ **dependencies** +Our makefile depends on you having recess, uglify.js, and jshint installed. To install, just run the following command in npm: + +``` +$ npm install recess uglify-js jshint -g +``` + ++ **build** - `make` +Runs the recess compiler to rebuild the `/less` files and compiles the docs pages. Requires recess and uglify-js. Read more in our docs » + ++ **test** - `make test` +Runs jshint and qunit tests headlessly in phantom js (used for ci). Depends on having phatomjs installed. + ++ **watch** - `make watch` +This is a convenience method for watching just Less files and automatically building them whenever you save. Requires the Watchr gem. + + + +Authors +------- + +**Mark Otto** + ++ http://twitter.com/mdo ++ http://github.com/markdotto + +**Jacob Thornton** + ++ http://twitter.com/fat ++ http://github.com/fat + + + +Copyright and license +--------------------- + +Copyright 2012 Twitter, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this work except in compliance with the License. +You may obtain a copy of the License in the LICENSE file, or at: + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/test/public/bootstrap/docs/assets/css/bootstrap-responsive.css b/test/public/bootstrap/docs/assets/css/bootstrap-responsive.css new file mode 100644 index 0000000..4a189a1 --- /dev/null +++ b/test/public/bootstrap/docs/assets/css/bootstrap-responsive.css @@ -0,0 +1,754 @@ +/*! + * Bootstrap Responsive v2.0.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + overflow: hidden; + text-indent: 100%; + white-space: nowrap; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none; +} + +.visible-tablet { + display: none; +} + +.visible-desktop { + display: block; +} + +.hidden-phone { + display: block; +} + +.hidden-tablet { + display: block; +} + +.hidden-desktop { + display: none; +} + +@media (max-width: 767px) { + .visible-phone { + display: block; + } + .hidden-phone { + display: none; + } + .hidden-desktop { + display: block; + } + .visible-desktop { + display: none; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .visible-tablet { + display: block; + } + .hidden-tablet { + display: none; + } + .hidden-desktop { + display: block; + } + .visible-desktop { + display: none; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 18px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-group > label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .modal { + position: absolute; + top: 10px; + right: 10px; + left: 10px; + width: auto; + margin: 0; + } + .modal.fade.in { + top: auto; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top { + margin-right: -20px; + margin-left: -20px; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row { + margin-left: 0; + } + .row > [class*="span"], + .row-fluid > [class*="span"] { + display: block; + float: none; + width: auto; + margin: 0; + } + .thumbnails [class*="span"] { + width: auto; + } + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + width: auto; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 20px; + } + .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.762430939%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span12 { + width: 99.999999993%; + } + .row-fluid > .span11 { + width: 91.436464082%; + } + .row-fluid > .span10 { + width: 82.87292817100001%; + } + .row-fluid > .span9 { + width: 74.30939226%; + } + .row-fluid > .span8 { + width: 65.74585634900001%; + } + .row-fluid > .span7 { + width: 57.182320438000005%; + } + .row-fluid > .span6 { + width: 48.618784527%; + } + .row-fluid > .span5 { + width: 40.055248616%; + } + .row-fluid > .span4 { + width: 31.491712705%; + } + .row-fluid > .span3 { + width: 22.928176794%; + } + .row-fluid > .span2 { + width: 14.364640883%; + } + .row-fluid > .span1 { + width: 5.801104972%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 714px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 652px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 590px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 528px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 466px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 404px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 342px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 280px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 218px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 156px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 94px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 32px; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top { + position: static; + margin-bottom: 18px; + } + .navbar-fixed-top .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .navbar .nav-collapse { + clear: left; + } + .navbar .nav { + float: none; + margin: 0 0 9px; + } + .navbar .nav > li { + float: none; + } + .navbar .nav > li > a { + margin-bottom: 2px; + } + .navbar .nav > .divider-vertical { + display: none; + } + .navbar .nav .nav-header { + color: #999999; + text-shadow: none; + } + .navbar .nav > li > a, + .navbar .dropdown-menu a { + padding: 6px 15px; + font-weight: bold; + color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .navbar .dropdown-menu li + li a { + margin-bottom: 2px; + } + .navbar .nav > li > a:hover, + .navbar .dropdown-menu a:hover { + background-color: #222222; + } + .navbar .dropdown-menu { + position: static; + top: auto; + left: auto; + display: block; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .navbar .dropdown-menu:before, + .navbar .dropdown-menu:after { + display: none; + } + .navbar .dropdown-menu .divider { + display: none; + } + .navbar-form, + .navbar-search { + float: none; + padding: 9px 15px; + margin: 9px 0; + border-top: 1px solid #222222; + border-bottom: 1px solid #222222; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar .nav.pull-right { + float: none; + margin-left: 0; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } + .btn-navbar { + display: block; + } + .nav-collapse { + height: 0; + overflow: hidden; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + margin-left: 30px; + } + .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid > [class*="span"] { + float: left; + margin-left: 2.564102564%; + } + .row-fluid > [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid > .span12 { + width: 100%; + } + .row-fluid > .span11 { + width: 91.45299145300001%; + } + .row-fluid > .span10 { + width: 82.905982906%; + } + .row-fluid > .span9 { + width: 74.358974359%; + } + .row-fluid > .span8 { + width: 65.81196581200001%; + } + .row-fluid > .span7 { + width: 57.264957265%; + } + .row-fluid > .span6 { + width: 48.717948718%; + } + .row-fluid > .span5 { + width: 40.170940171000005%; + } + .row-fluid > .span4 { + width: 31.623931624%; + } + .row-fluid > .span3 { + width: 23.076923077%; + } + .row-fluid > .span2 { + width: 14.529914530000001%; + } + .row-fluid > .span1 { + width: 5.982905983%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1160px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1060px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 960px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 860px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 760px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 660px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 560px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 460px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 360px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 260px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 160px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 60px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } +} diff --git a/test/public/bootstrap/docs/assets/css/bootstrap.css b/test/public/bootstrap/docs/assets/css/bootstrap.css new file mode 100644 index 0000000..632d836 --- /dev/null +++ b/test/public/bootstrap/docs/assets/css/bootstrap.css @@ -0,0 +1,4766 @@ +/*! + * Bootstrap v2.0.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + height: auto; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + overflow: hidden; + text-indent: 100%; + white-space: nowrap; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 28px; + /* Make inputs at least the height of their button counterpart */ + + /* Makes inputs behave like true block-level elements */ + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover { + color: #005580; + text-decoration: underline; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + margin-left: 20px; +} + +.container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid > [class*="span"] { + float: left; + margin-left: 2.127659574%; +} + +.row-fluid > [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid > .span12 { + width: 99.99999998999999%; +} + +.row-fluid > .span11 { + width: 91.489361693%; +} + +.row-fluid > .span10 { + width: 82.97872339599999%; +} + +.row-fluid > .span9 { + width: 74.468085099%; +} + +.row-fluid > .span8 { + width: 65.95744680199999%; +} + +.row-fluid > .span7 { + width: 57.446808505%; +} + +.row-fluid > .span6 { + width: 48.93617020799999%; +} + +.row-fluid > .span5 { + width: 40.425531911%; +} + +.row-fluid > .span4 { + width: 31.914893614%; +} + +.row-fluid > .span3 { + width: 23.404255317%; +} + +.row-fluid > .span2 { + width: 14.89361702%; +} + +.row-fluid > .span1 { + width: 6.382978723%; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; +} + +p small { + font-size: 11px; + color: #999999; +} + +.lead { + margin-bottom: 18px; + font-size: 20px; + font-weight: 200; + line-height: 27px; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + font-family: inherit; + font-weight: bold; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + color: #999999; +} + +h1 { + font-size: 30px; + line-height: 36px; +} + +h1 small { + font-size: 18px; +} + +h2 { + font-size: 24px; + line-height: 36px; +} + +h2 small { + font-size: 18px; +} + +h3 { + font-size: 18px; + line-height: 27px; +} + +h3 small { + font-size: 14px; +} + +h4, +h5, +h6 { + line-height: 18px; +} + +h4 { + font-size: 14px; +} + +h4 small { + font-size: 12px; +} + +h5 { + font-size: 12px; +} + +h6 { + font-size: 11px; + color: #999999; + text-transform: uppercase; +} + +.page-header { + padding-bottom: 17px; + margin: 18px 0; + border-bottom: 1px solid #eeeeee; +} + +.page-header h1 { + line-height: 1; +} + +ul, +ol { + padding: 0; + margin: 0 0 9px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +ul { + list-style: disc; +} + +ol { + list-style: decimal; +} + +li { + line-height: 18px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +dl { + margin-bottom: 18px; +} + +dt, +dd { + line-height: 18px; +} + +dt { + font-weight: bold; + line-height: 17px; +} + +dd { + margin-left: 9px; +} + +.dl-horizontal dt { + float: left; + width: 120px; + clear: left; + text-align: right; +} + +.dl-horizontal dd { + margin-left: 130px; +} + +hr { + margin: 18px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +.muted { + color: #999999; +} + +abbr[title] { + cursor: help; + border-bottom: 1px dotted #ddd; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 18px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 16px; + font-weight: 300; + line-height: 22.5px; +} + +blockquote small { + display: block; + line-height: 18px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 18px; + font-style: normal; + line-height: 18px; +} + +small { + font-size: 100%; +} + +cite { + font-style: normal; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 8.5px; + margin: 0 0 9px; + font-size: 12.025px; + line-height: 18px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 18px; +} + +pre code { + padding: 0; + color: inherit; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 18px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 27px; + font-size: 19.5px; + line-height: 36px; + color: #333333; + border: 0; + border-bottom: 1px solid #eee; +} + +legend small { + font-size: 13.5px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 13px; + font-weight: normal; + line-height: 18px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; + color: #333333; +} + +input, +textarea, +select, +.uneditable-input { + display: inline-block; + width: 210px; + height: 18px; + padding: 4px; + margin-bottom: 9px; + font-size: 13px; + line-height: 18px; + color: #555555; + border: 1px solid #cccccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +label input, +label textarea, +label select { + display: block; +} + +input[type="image"], +input[type="checkbox"], +input[type="radio"] { + width: auto; + height: auto; + padding: 0; + margin: 3px 0; + *margin-top: 0; + line-height: normal; + cursor: pointer; + border: 0 \9; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +input[type="image"] { + border: 0; +} + +input[type="file"] { + width: auto; + padding: initial; + line-height: initial; + background-color: #ffffff; + background-color: initial; + border: initial; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +input[type="button"], +input[type="reset"], +input[type="submit"] { + width: auto; + height: auto; +} + +select, +input[type="file"] { + height: 28px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 28px; +} + +input[type="file"] { + line-height: 18px \9; +} + +select { + width: 220px; + background-color: #ffffff; +} + +select[multiple], +select[size] { + height: auto; +} + +input[type="image"] { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +textarea { + height: auto; +} + +input[type="hidden"] { + display: none; +} + +.radio, +.checkbox { + padding-left: 18px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -18px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +input, +textarea { + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -ms-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +input:focus, +textarea:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus, +select:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input { + float: none; + margin-left: 0; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 930px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 850px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 770px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 690px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 610px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 530px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 450px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 370px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 290px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 210px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 130px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 50px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; + border-color: #ddd; +} + +.control-group.warning > label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; + border-color: #c09853; +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: 0 0 6px #dbc59e; + -moz-box-shadow: 0 0 6px #dbc59e; + box-shadow: 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error > label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; + border-color: #b94a48; +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: 0 0 6px #d59392; + -moz-box-shadow: 0 0 6px #d59392; + box-shadow: 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success > label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; + border-color: #468847; +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: 0 0 6px #7aba7b; + -moz-box-shadow: 0 0 6px #7aba7b; + box-shadow: 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +input:focus:required:invalid, +textarea:focus:required:invalid, +select:focus:required:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:required:invalid:focus, +textarea:focus:required:invalid:focus, +select:focus:required:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 17px 20px 18px; + margin-top: 18px; + margin-bottom: 18px; + background-color: #eeeeee; + border-top: 1px solid #ddd; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.uneditable-input { + display: block; + cursor: not-allowed; + background-color: #ffffff; + border-color: #eee; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +:-moz-placeholder { + color: #999999; +} + +::-webkit-input-placeholder { + color: #999999; +} + +.help-block, +.help-inline { + color: #555555; +} + +.help-block { + display: block; + margin-bottom: 9px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-prepend, +.input-append { + margin-bottom: 5px; +} + +.input-prepend input, +.input-append input, +.input-prepend select, +.input-append select, +.input-prepend .uneditable-input, +.input-append .uneditable-input { + *margin-left: 0; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend input:focus, +.input-append input:focus, +.input-prepend select:focus, +.input-append select:focus, +.input-prepend .uneditable-input:focus, +.input-append .uneditable-input:focus { + position: relative; + z-index: 2; +} + +.input-prepend .uneditable-input, +.input-append .uneditable-input { + border-left-color: #ccc; +} + +.input-prepend .add-on, +.input-append .add-on { + display: inline-block; + width: auto; + height: 18px; + min-width: 16px; + padding: 4px 5px; + font-weight: normal; + line-height: 18px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + vertical-align: middle; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-prepend .add-on, +.input-append .add-on, +.input-prepend .btn, +.input-append .btn { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-prepend .active, +.input-append .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-append input, +.input-append select .uneditable-input { + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-append .uneditable-input { + border-right-color: #ccc; + border-left-color: #eee; +} + +.input-append .add-on, +.input-append .btn { + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.search-query { + padding-right: 14px; + padding-left: 14px; + margin-bottom: 0; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + margin-bottom: 0; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 9px; +} + +legend + .control-group { + margin-top: 18px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 18px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 140px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 160px; + *margin-left: 0; +} + +.form-horizontal .help-block { + margin-top: 9px; + margin-bottom: 0; +} + +.form-horizontal .form-actions { + padding-left: 160px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 18px; +} + +.table th, +.table td { + padding: 8px; + line-height: 18px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapsed; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child th:first-child, +.table-bordered tbody:first-child tr:first-child td:first-child { + -webkit-border-radius: 4px 0 0 0; + -moz-border-radius: 4px 0 0 0; + border-radius: 4px 0 0 0; +} + +.table-bordered thead:first-child tr:first-child th:last-child, +.table-bordered tbody:first-child tr:first-child td:last-child { + -webkit-border-radius: 0 4px 0 0; + -moz-border-radius: 0 4px 0 0; + border-radius: 0 4px 0 0; +} + +.table-bordered thead:last-child tr:last-child th:first-child, +.table-bordered tbody:last-child tr:last-child td:first-child { + -webkit-border-radius: 0 0 0 4px; + -moz-border-radius: 0 0 0 4px; + border-radius: 0 0 0 4px; +} + +.table-bordered thead:last-child tr:last-child th:last-child, +.table-bordered tbody:last-child tr:last-child td:last-child { + -webkit-border-radius: 0 0 4px 0; + -moz-border-radius: 0 0 4px 0; + border-radius: 0 0 4px 0; +} + +.table-striped tbody tr:nth-child(odd) td, +.table-striped tbody tr:nth-child(odd) th { + background-color: #f9f9f9; +} + +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #f5f5f5; +} + +table .span1 { + float: none; + width: 44px; + margin-left: 0; +} + +table .span2 { + float: none; + width: 124px; + margin-left: 0; +} + +table .span3 { + float: none; + width: 204px; + margin-left: 0; +} + +table .span4 { + float: none; + width: 284px; + margin-left: 0; +} + +table .span5 { + float: none; + width: 364px; + margin-left: 0; +} + +table .span6 { + float: none; + width: 444px; + margin-left: 0; +} + +table .span7 { + float: none; + width: 524px; + margin-left: 0; +} + +table .span8 { + float: none; + width: 604px; + margin-left: 0; +} + +table .span9 { + float: none; + width: 684px; + margin-left: 0; +} + +table .span10 { + float: none; + width: 764px; + margin-left: 0; +} + +table .span11 { + float: none; + width: 844px; + margin-left: 0; +} + +table .span12 { + float: none; + width: 924px; + margin-left: 0; +} + +table .span13 { + float: none; + width: 1004px; + margin-left: 0; +} + +table .span14 { + float: none; + width: 1084px; + margin-left: 0; +} + +table .span15 { + float: none; + width: 1164px; + margin-left: 0; +} + +table .span16 { + float: none; + width: 1244px; + margin-left: 0; +} + +table .span17 { + float: none; + width: 1324px; + margin-left: 0; +} + +table .span18 { + float: none; + width: 1404px; + margin-left: 0; +} + +table .span19 { + float: none; + width: 1484px; + margin-left: 0; +} + +table .span20 { + float: none; + width: 1564px; + margin-left: 0; +} + +table .span21 { + float: none; + width: 1644px; + margin-left: 0; +} + +table .span22 { + float: none; + width: 1724px; + margin-left: 0; +} + +table .span23 { + float: none; + width: 1804px; + margin-left: 0; +} + +table .span24 { + float: none; + width: 1884px; + margin-left: 0; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +[class^="icon-"]:last-child, +[class*=" icon-"]:last-child { + *margin-left: 0; +} + +.icon-white { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + background-position: -384px -120px; +} + +.icon-folder-open { + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; + opacity: 0.3; + filter: alpha(opacity=30); +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown:hover .caret, +.open.dropdown .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 4px 0; + margin: 0; + list-style: none; + background-color: #ffffff; + border-color: #ccc; + border-color: rgba(0, 0, 0, 0.2); + border-style: solid; + border-width: 1px; + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + border-radius: 0 0 5px 5px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu a { + display: block; + padding: 3px 15px; + clear: both; + font-weight: normal; + line-height: 18px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu li > a:hover, +.dropdown-menu .active > a, +.dropdown-menu .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #0088cc; +} + +.dropdown.open { + *z-index: 1000; +} + +.dropdown.open .dropdown-toggle { + color: #ffffff; + background: #ccc; + background: rgba(0, 0, 0, 0.3); +} + +.dropdown.open .dropdown-menu { + display: block; +} + +.pull-right .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: "\2191"; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.typeahead { + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 5px; + margin-bottom: 5px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -ms-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -ms-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 10px 4px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 13px; + line-height: 18px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + background-color: #e6e6e6; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -ms-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-color: #e6e6e6; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 9px 14px; + font-size: 15px; + line-height: normal; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.btn-large [class^="icon-"] { + margin-top: 1px; +} + +.btn-small { + padding: 5px 9px; + font-size: 11px; + line-height: 16px; +} + +.btn-small [class^="icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 2px 6px; + font-size: 11px; + line-height: 14px; +} + +.btn-primary, +.btn-primary:hover, +.btn-warning, +.btn-warning:hover, +.btn-danger, +.btn-danger:hover, +.btn-success, +.btn-success:hover, +.btn-info, +.btn-info:hover, +.btn-inverse, +.btn-inverse:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn-primary { + background-color: #c77404; + background-image: linear-gradient(top, #c76004, #c79104); + background-image: -ms-linear-gradient(top, #c76004, #c79104); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#c76004), to(#c79104)); + background-image: -webkit-linear-gradient(top, #c76004, #c79104); + background-image: -o-linear-gradient(top, #c76004, #c79104); + background-image: -moz-linear-gradient(top, #c76004, #c79104); + background-repeat: repeat-x; + border-color: #c79104 #c79104 #7c5a02; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#c76004', endColorstr='#c79104', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + background-color: #c79104; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #956c03 \9; +} + +.btn-warning { + background-color: #faa732; + background-image: linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + background-color: #f89406; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + background-color: #da4f49; + background-image: linear-gradient(top, #ee5f5b, #bd362f); + background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + background-color: #bd362f; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + background-color: #5bb75b; + background-image: linear-gradient(top, #62c462, #51a351); + background-image: -ms-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + background-color: #51a351; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + background-color: #49afcd; + background-image: linear-gradient(top, #5bc0de, #2f96b4); + background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + background-color: #2f96b4; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + background-color: #414141; + background-image: linear-gradient(top, #555555, #222222); + background-image: -ms-linear-gradient(top, #555555, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222)); + background-image: -webkit-linear-gradient(top, #555555, #222222); + background-image: -o-linear-gradient(top, #555555, #222222); + background-image: -moz-linear-gradient(top, #555555, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + background-color: #222222; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 2px; + *padding-bottom: 2px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-group { + position: relative; + *margin-left: .3em; + *zoom: 1; +} + +.btn-group:before, +.btn-group:after { + display: table; + content: ""; +} + +.btn-group:after { + clear: both; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 9px; + margin-bottom: 9px; +} + +.btn-toolbar .btn-group { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group .btn { + position: relative; + float: left; + margin-left: -1px; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group .btn:last-child, +.btn-group .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group .btn.large:last-child, +.btn-group .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group .btn:hover, +.btn-group .btn:focus, +.btn-group .btn:active, +.btn-group .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group .dropdown-toggle { + *padding-top: 3px; + padding-right: 8px; + *padding-bottom: 3px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group .btn-mini.dropdown-toggle { + *padding-top: 1px; + padding-right: 5px; + *padding-bottom: 1px; + padding-left: 5px; +} + +.btn-group .btn-small.dropdown-toggle { + *padding-top: 4px; + *padding-bottom: 4px; +} + +.btn-group .btn-large.dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} + +.btn-group.open { + *z-index: 1000; +} + +.btn-group.open .dropdown-menu { + display: block; + margin-top: 1px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn .caret { + margin-top: 7px; + margin-left: 0; +} + +.btn:hover .caret, +.open.btn-group .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.btn-mini .caret { + margin-top: 5px; +} + +.btn-small .caret { + margin-top: 6px; +} + +.btn-large .caret { + margin-top: 6px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 0.75; + filter: alpha(opacity=75); +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + color: #c09853; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert-heading { + color: inherit; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 18px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover { + text-decoration: none; + background-color: #eeeeee; +} + +.nav .nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 18px; + color: #ffffff; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; + background-color: #e56e05; + background-image: -moz-linear-gradient(top, #f97805, #c76004); + background-image: -ms-linear-gradient(top, #f97805, #c76004); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f97805), to(#c76004)); + background-image: -webkit-linear-gradient(top, #f97805, #c76004); + background-image: -o-linear-gradient(top, #f97805, #c76004); + background-image: linear-gradient(top, #f97805, #c76004); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f97805', endColorstr='#c76004', GradientType=0); +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 8px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 18px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.nav-tabs.nav-stacked > li > a:hover { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu, +.nav-pills .dropdown-menu { + margin-top: 1px; + border-width: 1px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.nav-tabs .dropdown-toggle .caret, +.nav-pills .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav-tabs .dropdown-toggle:hover .caret, +.nav-pills .dropdown-toggle:hover .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +.nav-tabs .active .dropdown-toggle .caret, +.nav-pills .active .dropdown-toggle .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.nav > .dropdown.active > a:hover { + color: #000000; + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > .open.active > a:hover { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav .open .caret, +.nav .open.active .caret, +.nav .open a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + display: table; + width: 100%; +} + +.tabs-below .nav-tabs, +.tabs-right .nav-tabs, +.tabs-left .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below .nav-tabs > li > a:hover { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below .nav-tabs .active > a, +.tabs-below .nav-tabs .active > a:hover { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left .nav-tabs > li, +.tabs-right .nav-tabs > li { + float: none; +} + +.tabs-left .nav-tabs > li > a, +.tabs-right .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left .nav-tabs > li > a:hover { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left .nav-tabs .active > a, +.tabs-left .nav-tabs .active > a:hover { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right .nav-tabs > li > a:hover { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right .nav-tabs .active > a, +.tabs-right .nav-tabs .active > a:hover { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 18px; + overflow: visible; +} + +.navbar-inner { + padding-right: 5px; + padding-left: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1); +} + +.navbar .container { + width: auto; +} + +.btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + background-color: #2c2c2c; + background-image: -moz-linear-gradient(top, #333333, #222222); + background-image: -ms-linear-gradient(top, #333333, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222)); + background-image: -webkit-linear-gradient(top, #333333, #222222); + background-image: -o-linear-gradient(top, #333333, #222222); + background-image: linear-gradient(top, #333333, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.btn-navbar:hover, +.btn-navbar:active, +.btn-navbar.active, +.btn-navbar.disabled, +.btn-navbar[disabled] { + background-color: #222222; +} + +.btn-navbar:active, +.btn-navbar.active { + background-color: #080808 \9; +} + +.btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.nav-collapse.collapse { + height: auto; +} + +.navbar { + color: #999999; +} + +.navbar .brand:hover { + text-decoration: none; +} + +.navbar .brand { + display: block; + float: left; + padding: 8px 20px 12px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + line-height: 1; + color: #ffffff; +} + +.navbar .navbar-text { + margin-bottom: 0; + line-height: 40px; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 6px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 6px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 9px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + color: #ffffff; + background-color: #626262; + border: 1px solid #151515; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -ms-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-search .search-query:focus, +.navbar-search .search-query.focused { + padding: 5px 10px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; +} + +.navbar .nav > li { + display: block; + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 10px 11px; + line-height: 19px; + color: #999999; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar .nav > li > a:hover { + color: #ffffff; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav .active > a, +.navbar .nav .active > a:hover { + color: #ffffff; + text-decoration: none; + background-color: #222222; +} + +.navbar .divider-vertical { + width: 1px; + height: 40px; + margin: 0 9px; + overflow: hidden; + background-color: #222222; + border-right: 1px solid #333333; +} + +.navbar .nav.pull-right { + margin-right: 0; + margin-left: 10px; +} + +.navbar .dropdown-menu { + margin-top: 1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.navbar .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav .dropdown-toggle .caret, +.navbar .nav .open.dropdown .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar .nav .active .caret { + opacity: 1; + filter: alpha(opacity=100); +} + +.navbar .nav .open > .dropdown-toggle, +.navbar .nav .active > .dropdown-toggle, +.navbar .nav .open.active > .dropdown-toggle { + background-color: transparent; +} + +.navbar .nav .active > .dropdown-toggle:hover { + color: #ffffff; +} + +.navbar .nav.pull-right .dropdown-menu, +.navbar .nav .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .nav.pull-right .dropdown-menu:before, +.navbar .nav .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .nav.pull-right .dropdown-menu:after, +.navbar .nav .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.breadcrumb { + padding: 7px 14px; + margin: 0 0 18px; + list-style: none; + background-color: #fbfbfb; + background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5)); + background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5); + background-image: -o-linear-gradient(top, #ffffff, #f5f5f5); + background-image: linear-gradient(top, #ffffff, #f5f5f5); + background-repeat: repeat-x; + border: 1px solid #ddd; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0); + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.breadcrumb li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb .divider { + padding: 0 5px; + color: #999999; +} + +.breadcrumb .active a { + color: #333333; +} + +.pagination { + height: 36px; + margin: 18px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination li { + display: inline; +} + +.pagination a { + float: left; + padding: 0 14px; + line-height: 34px; + text-decoration: none; + border: 1px solid #ddd; + border-left-width: 0; +} + +.pagination a:hover, +.pagination .active a { + background-color: #f5f5f5; +} + +.pagination .active a { + color: #999999; + cursor: default; +} + +.pagination .disabled span, +.pagination .disabled a, +.pagination .disabled a:hover { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination li:first-child a { + border-left-width: 1px; + -webkit-border-radius: 3px 0 0 3px; + -moz-border-radius: 3px 0 0 3px; + border-radius: 3px 0 0 3px; +} + +.pagination li:last-child a { + -webkit-border-radius: 0 3px 3px 0; + -moz-border-radius: 0 3px 3px 0; + border-radius: 0 3px 3px 0; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pager { + margin-bottom: 18px; + margin-left: 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next a { + float: right; +} + +.pager .previous a { + float: left; +} + +.pager .disabled a, +.pager .disabled a:hover { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-open .dropdown-menu { + z-index: 2050; +} + +.modal-open .dropdown.open { + *z-index: 2050; +} + +.modal-open .popover { + z-index: 2060; +} + +.modal-open .tooltip { + z-index: 2070; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 50%; + left: 50%; + z-index: 1050; + width: 560px; + margin: -250px 0 0 -280px; + overflow: auto; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -ms-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 50%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-body { + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.tooltip { + position: absolute; + z-index: 1020; + display: block; + padding: 5px; + font-size: 11px; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + margin-top: -2px; +} + +.tooltip.right { + margin-left: 2px; +} + +.tooltip.bottom { + margin-top: 2px; +} + +.tooltip.left { + margin-left: -2px; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + padding: 5px; +} + +.popover.top { + margin-top: -5px; +} + +.popover.right { + margin-left: 5px; +} + +.popover.bottom { + margin-top: 5px; +} + +.popover.left { + margin-left: -5px; +} + +.popover.top .arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top: 5px solid #000000; + border-right: 5px solid transparent; + border-left: 5px solid transparent; +} + +.popover.right .arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-right: 5px solid #000000; + border-bottom: 5px solid transparent; +} + +.popover.bottom .arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-right: 5px solid transparent; + border-bottom: 5px solid #000000; + border-left: 5px solid transparent; +} + +.popover.left .arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-top: 5px solid transparent; + border-bottom: 5px solid transparent; + border-left: 5px solid #000000; +} + +.popover .arrow { + position: absolute; + width: 0; + height: 0; +} + +.popover-inner { + width: 280px; + padding: 3px; + overflow: hidden; + background: #000000; + background: rgba(0, 0, 0, 0.8); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); +} + +.popover-title { + padding: 9px 15px; + line-height: 1; + background-color: #f5f5f5; + border-bottom: 1px solid #eee; + -webkit-border-radius: 3px 3px 0 0; + -moz-border-radius: 3px 3px 0 0; + border-radius: 3px 3px 0 0; +} + +.popover-content { + padding: 14px; + background-color: #ffffff; + -webkit-border-radius: 0 0 3px 3px; + -moz-border-radius: 0 0 3px 3px; + border-radius: 0 0 3px 3px; + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.popover-content p, +.popover-content ul, +.popover-content ol { + margin-bottom: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.thumbnails > li { + float: left; + margin: 0 0 18px 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 1; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075); +} + +a.thumbnail:hover { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; +} + +.label { + padding: 1px 4px 2px; + font-size: 10.998px; + font-weight: bold; + line-height: 13px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: middle; + background-color: #999999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.label:hover { + color: #ffffff; + text-decoration: none; +} + +.label-important { + background-color: #b94a48; +} + +.label-important:hover { + background-color: #953b39; +} + +.label-warning { + background-color: #f89406; +} + +.label-warning:hover { + background-color: #c67605; +} + +.label-success { + background-color: #468847; +} + +.label-success:hover { + background-color: #356635; +} + +.label-info { + background-color: #3a87ad; +} + +.label-info:hover { + background-color: #2d6987; +} + +.label-inverse { + background-color: #333333; +} + +.label-inverse:hover { + background-color: #1a1a1a; +} + +.badge { + padding: 1px 9px 2px; + font-size: 12.025px; + font-weight: bold; + color: #ffffff; + white-space: nowrap; + background-color: #999999; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.badge:hover { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.badge-error { + background-color: #b94a48; +} + +.badge-error:hover { + background-color: #953b39; +} + +.badge-warning { + background-color: #f89406; +} + +.badge-warning:hover { + background-color: #c67605; +} + +.badge-success { + background-color: #468847; +} + +.badge-success:hover { + background-color: #356635; +} + +.badge-info { + background-color: #3a87ad; +} + +.badge-info:hover { + background-color: #2d6987; +} + +.badge-inverse { + background-color: #333333; +} + +.badge-inverse:hover { + background-color: #1a1a1a; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +.progress { + height: 18px; + margin-bottom: 18px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(top, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + width: 0; + height: 18px; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(top, #149bdf, #0480be); + background-image: -ms-linear-gradient(top, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -ms-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(top, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -ms-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(top, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0); +} + +.progress-success.progress-striped .bar { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -ms-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(top, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -ms-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0); +} + +.progress-warning.progress-striped .bar { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 18px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 18px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -ms-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel .item > img { + display: block; + line-height: 1; +} + +.carousel .active, +.carousel .next, +.carousel .prev { + display: block; +} + +.carousel .active { + left: 0; +} + +.carousel .next, +.carousel .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel .next { + left: 100%; +} + +.carousel .prev { + left: -100%; +} + +.carousel .next.left, +.carousel .prev.right { + left: 0; +} + +.carousel .active.left { + left: -100%; +} + +.carousel .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 10px 15px 5px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + color: #ffffff; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit p { + font-size: 18px; + font-weight: 200; + line-height: 27px; + color: inherit; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} diff --git a/test/public/bootstrap/docs/assets/css/docs.css b/test/public/bootstrap/docs/assets/css/docs.css new file mode 100644 index 0000000..b7e0c8d --- /dev/null +++ b/test/public/bootstrap/docs/assets/css/docs.css @@ -0,0 +1,841 @@ +/* Add additional stylesheets below +-------------------------------------------------- */ +/* + Bootstrap's documentation styles + Special styles for presenting Bootstrap's documentation and examples +*/ + + +/* Body and structure +-------------------------------------------------- */ +body { + position: relative; + padding-top: 90px; + background-color: #fff; + background-image: url(../img/grid-18px-masked.png); + background-repeat: repeat-x; + background-position: 0 40px; +} + + +/* Tweak navbar brand link to be super sleek +-------------------------------------------------- */ +.navbar-fixed-top .brand { + padding-right: 0; + padding-left: 0; + margin-left: 20px; + float: right; + font-weight: bold; + color: #000; + text-shadow: 0 1px 0 rgba(255,255,255,.1), 0 0 30px rgba(255,255,255,.125); + -webkit-transition: all .2s linear; + -moz-transition: all .2s linear; + transition: all .2s linear; +} +.navbar-fixed-top .brand:hover { + text-decoration: none; +} + + +/* Space out sub-sections more +-------------------------------------------------- */ +section { + padding-top: 60px; +} + +/* Faded out hr */ +hr.soften { + height: 1px; + margin: 54px 0; + background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + background-image: -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + background-image: -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); + border: 0; +} + + +/* Jumbotrons +-------------------------------------------------- */ +.jumbotron { + position: relative; +} +.jumbotron h1 { + margin-bottom: 9px; + font-size: 81px; + font-weight: bold; + letter-spacing: -1px; + line-height: 1; +} +.jumbotron p { + margin-bottom: 18px; + font-weight: 300; +} +.jumbotron .btn-large { + font-size: 20px; + font-weight: normal; + padding: 14px 24px; + margin-right: 10px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.jumbotron .btn-large small { + font-size: 14px; +} + +/* Masthead (docs home) */ +.masthead { + padding-top: 36px; + margin-bottom: 72px; +} +.masthead h1, +.masthead p { + text-align: center; +} +.masthead h1 { + margin-bottom: 18px; +} +.masthead p { + margin-left: 5%; + margin-right: 5%; + font-size: 30px; + line-height: 36px; +} + + +/* Specific jumbotrons +------------------------- */ +/* supporting docs pages */ +.subhead { + padding-bottom: 0; + margin-bottom: 9px; +} +.subhead h1 { + font-size: 54px; +} + +/* Subnav */ +.subnav { + width: 100%; + height: 36px; + background-color: #eeeeee; /* Old browsers */ + background-repeat: repeat-x; /* Repeat the gradient */ + background-image: -moz-linear-gradient(top, #f5f5f5 0%, #eeeeee 100%); /* FF3.6+ */ + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f5f5f5), color-stop(100%,#eeeeee)); /* Chrome,Safari4+ */ + background-image: -webkit-linear-gradient(top, #f5f5f5 0%,#eeeeee 100%); /* Chrome 10+,Safari 5.1+ */ + background-image: -ms-linear-gradient(top, #f5f5f5 0%,#eeeeee 100%); /* IE10+ */ + background-image: -o-linear-gradient(top, #f5f5f5 0%,#eeeeee 100%); /* Opera 11.10+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#eeeeee',GradientType=0 ); /* IE6-9 */ + background-image: linear-gradient(top, #f5f5f5 0%,#eeeeee 100%); /* W3C */ + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.subnav .nav { + margin-bottom: 0; +} +.subnav .nav > li > a { + margin: 0; + padding-top: 11px; + padding-bottom: 11px; + border-left: 1px solid #f5f5f5; + border-right: 1px solid #e5e5e5; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} +.subnav .nav > .active > a, +.subnav .nav > .active > a:hover { + padding-left: 13px; + color: #777; + background-color: #e9e9e9; + border-right-color: #ddd; + border-left: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0,0,0,.05); + -moz-box-shadow: inset 0 3px 5px rgba(0,0,0,.05); + box-shadow: inset 0 3px 5px rgba(0,0,0,.05); +} +.subnav .nav > .active > a .caret, +.subnav .nav > .active > a:hover .caret { + border-top-color: #777; +} +.subnav .nav > li:first-child > a, +.subnav .nav > li:first-child > a:hover { + border-left: 0; + padding-left: 12px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +.subnav .nav > li:last-child > a { + border-right: 0; +} +.subnav .dropdown-menu { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +/* Fixed subnav on scroll, but only for 980px and up (sorry IE!) */ +@media (min-width: 980px) { + .subnav-fixed { + position: fixed; + top: 40px; + left: 0; + right: 0; + z-index: 1020; /* 10 less than .navbar-fixed to prevent any overlap */ + border-color: #d5d5d5; + border-width: 0 0 1px; /* drop the border on the fixed edges */ + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1); + -moz-box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1); + box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); /* IE6-9 */ + } + .subnav-fixed .nav { + width: 938px; + margin: 0 auto; + padding: 0 1px; + } + .subnav .nav > li:first-child > a, + .subnav .nav > li:first-child > a:hover { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + } +} + + +/* Quick links +-------------------------------------------------- */ +.bs-links { + margin: 36px 0; +} +.quick-links { + min-height: 30px; + margin: 0; + padding: 5px 20px; + list-style: none; + text-align: center; + overflow: hidden; +} +.quick-links:first-child { + min-height: 0; +} +.quick-links li { + display: inline; + margin: 0 8px; + color: #999; +} +.quick-links .github-btn, +.quick-links .tweet-btn, +.quick-links .follow-btn { + position: relative; + top: 5px; +} + + +/* Marketing section of Overview +-------------------------------------------------- */ +.marketing .row { + margin-bottom: 9px; +} +.marketing h1 { + margin: 36px 0 27px; + font-size: 40px; + font-weight: 300; + text-align: center; +} +.marketing h2, +.marketing h3 { + font-weight: 300; +} +.marketing h2 { + font-size: 22px; +} +.marketing p { + margin-right: 10px; +} +.marketing .bs-icon { + float: left; + margin: 7px 10px 0 0; + opacity: .8; +} +.marketing .small-bs-icon { + float: left; + margin: 4px 5px 0 0; +} + + + +/* Footer +-------------------------------------------------- */ +.footer { + margin-top: 45px; + padding: 35px 0 36px; + border-top: 1px solid #e5e5e5; +} +.footer p { + margin-bottom: 0; + color: #555; +} + + + +/* Special grid styles +-------------------------------------------------- */ +.show-grid { + margin-top: 10px; + margin-bottom: 20px; +} +.show-grid [class*="span"] { + background-color: #eee; + text-align: center; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + min-height: 30px; + line-height: 30px; +} +.show-grid:hover [class*="span"] { + background: #ddd; +} +.show-grid .show-grid { + margin-top: 0; + margin-bottom: 0; +} +.show-grid .show-grid [class*="span"] { + background-color: #ccc; +} + + +/* Render mini layout previews +-------------------------------------------------- */ +.mini-layout { + border: 1px solid #ddd; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075); + -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075); + box-shadow: 0 1px 2px rgba(0,0,0,.075); +} +.mini-layout { + height: 240px; + margin-bottom: 20px; + padding: 9px; +} +.mini-layout div { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.mini-layout .mini-layout-body { + background-color: #dceaf4; + margin: 0 auto; + width: 70%; + height: 240px; +} +.mini-layout.fluid .mini-layout-sidebar, +.mini-layout.fluid .mini-layout-header, +.mini-layout.fluid .mini-layout-body { + float: left; +} +.mini-layout.fluid .mini-layout-sidebar { + background-color: #bbd8e9; + width: 20%; + height: 240px; +} +.mini-layout.fluid .mini-layout-body { + width: 77.5%; + margin-left: 2.5%; +} + + +/* Popover docs +-------------------------------------------------- */ +.popover-well { + min-height: 160px; +} +.popover-well .popover { + display: block; +} +.popover-well .popover-wrapper { + width: 50%; + height: 160px; + float: left; + margin-left: 55px; + position: relative; +} +.popover-well .popover-menu-wrapper { + height: 80px; +} +.large-bird { + margin: 5px 0 0 310px; + opacity: .1; +} + + +/* Download page +-------------------------------------------------- */ +.download .page-header { + margin-top: 36px; +} +.page-header .toggle-all { + margin-top: 5px; +} + +/* Space out h3s when following a section */ +.download h3 { + margin-bottom: 5px; +} +.download-builder input + h3, +.download-builder .checkbox + h3 { + margin-top: 9px; +} + +/* Fields for variables */ +.download-builder input[type=text] { + margin-bottom: 9px; + font-family: Menlo, Monaco, "Courier New", monospace; + font-size: 12px; + color: #d14; +} +.download-builder input[type=text]:focus { + background-color: #fff; +} + +/* Custom, larger checkbox labels */ +.download .checkbox { + padding: 6px 10px 6px 25px; + color: #555; + background-color: #f9f9f9; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + cursor: pointer; +} +.download .checkbox:hover { + color: #333; + background-color: #f5f5f5; +} +.download .checkbox small { + font-size: 12px; + color: #777; +} + +/* Variables section */ +#variables label { + margin-bottom: 0; +} + +/* Giant download button */ +.download-btn { + margin: 36px 0 108px; +} +#download p, +#download h4 { + max-width: 50%; + margin: 0 auto; + color: #999; + text-align: center; +} +#download h4 { + margin-bottom: 0; +} +#download p { + margin-bottom: 18px; +} +.download-btn .btn { + display: block; + width: auto; + padding: 19px 24px; + margin-bottom: 27px; + font-size: 30px; + line-height: 1; + text-align: center; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + + + +/* Color swatches on LESS docs page +-------------------------------------------------- */ +/* Sets the width of the td */ +.swatch-col { + width: 30px; +} +/* Le swatch */ +.swatch { + display: inline-block; + width: 30px; + height: 20px; + margin: -6px 0; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +/* For white swatches, give a border */ +.swatch-bordered { + width: 28px; + height: 18px; + border: 1px solid #eee; +} + + +/* Misc +-------------------------------------------------- */ + +/* Make tables spaced out a bit more */ +h2 + table, +h3 + table, +h4 + table, +h2 + .row { + margin-top: 5px; +} + +/* Example sites showcase */ +.example-sites img { + max-width: 100%; + margin: 0 auto; +} +.marketing-byline { + margin: -18px 0 27px; + font-size: 18px; + font-weight: 300; + line-height: 24px; + color: #999; + text-align: center; +} + +.scrollspy-example { + height: 200px; + overflow: auto; + position: relative; +} + +/* Remove bottom margin on example forms in wells */ +form.well { + padding: 14px; +} + +/* Tighten up spacing */ +.well hr { + margin: 18px 0; +} + +/* Fake the :focus state to demo it */ +.focused { + border-color: rgba(82,168,236,.8); + -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); + -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); + box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); + outline: 0; +} + +/* For input sizes, make them display block */ +.docs-input-sizes select, +.docs-input-sizes input[type=text] { + display: block; + margin-bottom: 9px; +} + +/* Icons +------------------------- */ +.the-icons { + margin-left: 0; + list-style: none; +} +.the-icons i:hover { + background-color: rgba(255,0,0,.25); +} + +/* Eaxmples page +------------------------- */ +.bootstrap-examples .thumbnail { + margin-bottom: 9px; + background-color: #fff; +} + +/* Responsive table +------------------------- */ +.responsive-utilities th small { + display: block; + font-weight: normal; + color: #999; +} +.responsive-utilities tbody th { + font-weight: normal; +} +.responsive-utilities td { + text-align: center; +} +.responsive-utilities td.is-visible { + color: #468847; + background-color: #dff0d8 !important; +} +.responsive-utilities td.is-hidden { + color: #ccc; + background-color: #f9f9f9 !important; +} + +/* Responsive tests +------------------------- */ +.responsive-utilities-test { + margin-top: 5px; + margin-left: 0; + list-style: none; + overflow: hidden; /* clear floats */ +} +.responsive-utilities-test li { + position: relative; + float: left; + width: 25%; + height: 43px; + font-size: 14px; + font-weight: bold; + line-height: 43px; + color: #999; + text-align: center; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.responsive-utilities-test li + li { + margin-left: 10px; +} +.responsive-utilities-test span { + position: absolute; + top: -1px; + left: -1px; + right: -1px; + bottom: -1px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.responsive-utilities-test span { + color: #468847; + background-color: #dff0d8; + border: 1px solid #d6e9c6; +} + + +/* Responsive Docs +-------------------------------------------------- */ +@media (max-width: 480px) { + + /* Reduce padding above jumbotron */ + body { + padding-top: 70px; + } + + /* Change up some type stuff */ + h2 { + margin-top: 27px; + } + h2 small { + display: block; + line-height: 18px; + } + h3 { + margin-top: 18px; + } + + /* Adjust the jumbotron */ + .jumbotron h1, + .jumbotron p { + text-align: center; + margin-right: 0; + } + .jumbotron h1 { + font-size: 45px; + margin-right: 0; + } + .jumbotron p { + margin-right: 0; + margin-left: 0; + font-size: 18px; + line-height: 24px; + } + .jumbotron .btn { + display: block; + font-size: 18px; + padding: 10px 14px; + margin: 0 auto 10px; + } + /* Masthead (home page jumbotron) */ + .masthead { + padding-top: 0; + } + + /* Don't space out quick links so much */ + .quick-links { + margin: 40px 0 0; + } + /* hide the bullets on mobile since our horizontal space is limited */ + .quick-links .divider { + display: none; + } + + /* center example sites */ + .example-sites { + margin-left: 0; + } + .example-sites > li { + float: none; + display: block; + max-width: 280px; + margin: 0 auto 18px; + text-align: center; + } + .example-sites .thumbnail > img { + max-width: 270px; + } + + table code { + white-space: normal; + word-wrap: break-word; + word-break: break-all; + } + + /* Modal example */ + .modal-example .modal { + position: relative; + top: auto; + right: auto; + bottom: auto; + left: auto; + } + +} + + +@media (max-width: 768px) { + + /* Remove any padding from the body */ + body { + padding-top: 0; + } + + /* Jumbotron buttons */ + .jumbotron .btn { + margin-bottom: 10px; + } + + /* Subnav */ + .subnav { + position: static; + top: auto; + z-index: auto; + width: auto; + height: auto; + background: #fff; /* whole background property since we use a background-image for gradient */ + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .subnav .nav > li { + float: none; + } + .subnav .nav > li > a { + border: 0; + } + .subnav .nav > li + li > a { + border-top: 1px solid #e5e5e5; + } + .subnav .nav > li:first-child > a, + .subnav .nav > li:first-child > a:hover { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; + } + + /* Popovers */ + .large-bird { + display: none; + } + .popover-well .popover-wrapper { + margin-left: 0; + } + + /* Space out the show-grid examples */ + .show-grid [class*="span"] { + margin-bottom: 5px; + } + + /* Unfloat the back to top link in footer */ + .footer .pull-right { + float: none; + } + .footer p { + margin-bottom: 9px; + } + +} + + +@media (min-width: 480px) and (max-width: 768px) { + + /* Scale down the jumbotron content */ + .jumbotron h1 { + font-size: 54px; + } + .jumbotron p { + margin-right: 0; + margin-left: 0; + } + +} + + +@media (min-width: 768px) and (max-width: 980px) { + + /* Remove any padding from the body */ + body { + padding-top: 0; + } + + /* Scale down the jumbotron content */ + .jumbotron h1 { + font-size: 72px; + } + +} + + +@media (max-width: 980px) { + + /* Unfloat brand */ + .navbar-fixed-top .brand { + float: left; + margin-left: 0; + padding-left: 10px; + padding-right: 10px; + } + + /* Inline-block quick links for more spacing */ + .quick-links li { + display: inline-block; + margin: 5px; + } + +} + + +/* LARGE DESKTOP SCREENS */ +@media (min-width: 1210px) { + + /* Update subnav container */ + .subnav-fixed .nav { + width: 1168px; /* 2px less to account for left/right borders being removed when in fixed mode */ + } + +} diff --git a/test/public/bootstrap/docs/assets/ico/apple-touch-icon-114-precomposed.png b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-114-precomposed.png new file mode 100644 index 0000000..f1c93e6 Binary files /dev/null and b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-114-precomposed.png differ diff --git a/test/public/bootstrap/docs/assets/ico/apple-touch-icon-144-precomposed.png b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-144-precomposed.png new file mode 100644 index 0000000..3c80087 Binary files /dev/null and b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-144-precomposed.png differ diff --git a/test/public/bootstrap/docs/assets/ico/apple-touch-icon-57-precomposed.png b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-57-precomposed.png new file mode 100644 index 0000000..34b8dd6 Binary files /dev/null and b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-57-precomposed.png differ diff --git a/test/public/bootstrap/docs/assets/ico/apple-touch-icon-72-precomposed.png b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-72-precomposed.png new file mode 100644 index 0000000..f77bd6c Binary files /dev/null and b/test/public/bootstrap/docs/assets/ico/apple-touch-icon-72-precomposed.png differ diff --git a/test/public/bootstrap/docs/assets/ico/favicon.ico b/test/public/bootstrap/docs/assets/ico/favicon.ico new file mode 100644 index 0000000..e1c310e Binary files /dev/null and b/test/public/bootstrap/docs/assets/ico/favicon.ico differ diff --git a/test/public/bootstrap/docs/assets/img/bird.png b/test/public/bootstrap/docs/assets/img/bird.png new file mode 100644 index 0000000..903e4c7 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/bird.png differ diff --git a/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-01.jpg b/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-01.jpg new file mode 100644 index 0000000..135c9ba Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-01.jpg differ diff --git a/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-02.jpg b/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-02.jpg new file mode 100644 index 0000000..704e5df Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-02.jpg differ diff --git a/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-03.jpg b/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-03.jpg new file mode 100644 index 0000000..430fde2 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/bootstrap-mdo-sfmoma-03.jpg differ diff --git a/test/public/bootstrap/docs/assets/img/browsers.png b/test/public/bootstrap/docs/assets/img/browsers.png new file mode 100644 index 0000000..73b668d Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/browsers.png differ diff --git a/test/public/bootstrap/docs/assets/img/example-sites/fleetio.png b/test/public/bootstrap/docs/assets/img/example-sites/fleetio.png new file mode 100644 index 0000000..9207b0c Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/example-sites/fleetio.png differ diff --git a/test/public/bootstrap/docs/assets/img/example-sites/jshint.png b/test/public/bootstrap/docs/assets/img/example-sites/jshint.png new file mode 100644 index 0000000..ac7086d Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/example-sites/jshint.png differ diff --git a/test/public/bootstrap/docs/assets/img/example-sites/kippt.png b/test/public/bootstrap/docs/assets/img/example-sites/kippt.png new file mode 100644 index 0000000..4afa772 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/example-sites/kippt.png differ diff --git a/test/public/bootstrap/docs/assets/img/example-sites/soundready.png b/test/public/bootstrap/docs/assets/img/example-sites/soundready.png new file mode 100644 index 0000000..2675ff9 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/example-sites/soundready.png differ diff --git a/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-fluid.jpg b/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-fluid.jpg new file mode 100644 index 0000000..151b987 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-fluid.jpg differ diff --git a/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-hero.jpg b/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-hero.jpg new file mode 100644 index 0000000..cd4a321 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-hero.jpg differ diff --git a/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-starter.jpg b/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-starter.jpg new file mode 100644 index 0000000..09c8a06 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/examples/bootstrap-example-starter.jpg differ diff --git a/test/public/bootstrap/docs/assets/img/github-16px.png b/test/public/bootstrap/docs/assets/img/github-16px.png new file mode 100644 index 0000000..c99ab23 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/github-16px.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons-halflings-white.png b/test/public/bootstrap/docs/assets/img/glyphicons-halflings-white.png new file mode 100644 index 0000000..3bf6484 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons-halflings-white.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons-halflings.png b/test/public/bootstrap/docs/assets/img/glyphicons-halflings.png new file mode 100644 index 0000000..79bc568 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons-halflings.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_009_magic.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_009_magic.png new file mode 100644 index 0000000..f1cfb37 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_009_magic.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_042_group.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_042_group.png new file mode 100644 index 0000000..be5c6f9 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_042_group.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_079_podium.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_079_podium.png new file mode 100644 index 0000000..20b7c99 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_079_podium.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_082_roundabout.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_082_roundabout.png new file mode 100644 index 0000000..e3a6487 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_082_roundabout.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_155_show_thumbnails.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_155_show_thumbnails.png new file mode 100644 index 0000000..751e3b7 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_155_show_thumbnails.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_163_iphone.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_163_iphone.png new file mode 100644 index 0000000..926df7e Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_163_iphone.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_214_resize_small.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_214_resize_small.png new file mode 100644 index 0000000..707d9e0 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_214_resize_small.png differ diff --git a/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_266_book_open.png b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_266_book_open.png new file mode 100644 index 0000000..ab04b4a Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/glyphicons/glyphicons_266_book_open.png differ diff --git a/test/public/bootstrap/docs/assets/img/grid-18px-masked.png b/test/public/bootstrap/docs/assets/img/grid-18px-masked.png new file mode 100644 index 0000000..1bc82b0 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/grid-18px-masked.png differ diff --git a/test/public/bootstrap/docs/assets/img/icon-css3.png b/test/public/bootstrap/docs/assets/img/icon-css3.png new file mode 100644 index 0000000..58e1072 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/icon-css3.png differ diff --git a/test/public/bootstrap/docs/assets/img/icon-github.png b/test/public/bootstrap/docs/assets/img/icon-github.png new file mode 100644 index 0000000..1a5fb78 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/icon-github.png differ diff --git a/test/public/bootstrap/docs/assets/img/icon-html5.png b/test/public/bootstrap/docs/assets/img/icon-html5.png new file mode 100644 index 0000000..1e87883 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/icon-html5.png differ diff --git a/test/public/bootstrap/docs/assets/img/icon-twitter.png b/test/public/bootstrap/docs/assets/img/icon-twitter.png new file mode 100644 index 0000000..a471654 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/icon-twitter.png differ diff --git a/test/public/bootstrap/docs/assets/img/less-logo-large.png b/test/public/bootstrap/docs/assets/img/less-logo-large.png new file mode 100644 index 0000000..cb56637 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/less-logo-large.png differ diff --git a/test/public/bootstrap/docs/assets/img/less-small.png b/test/public/bootstrap/docs/assets/img/less-small.png new file mode 100644 index 0000000..93ea597 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/less-small.png differ diff --git a/test/public/bootstrap/docs/assets/img/responsive-illustrations.png b/test/public/bootstrap/docs/assets/img/responsive-illustrations.png new file mode 100644 index 0000000..6ca0f07 Binary files /dev/null and b/test/public/bootstrap/docs/assets/img/responsive-illustrations.png differ diff --git a/test/public/bootstrap/docs/assets/js/README.md b/test/public/bootstrap/docs/assets/js/README.md new file mode 100644 index 0000000..b58fa1d --- /dev/null +++ b/test/public/bootstrap/docs/assets/js/README.md @@ -0,0 +1,106 @@ +## 2.0 BOOTSTRAP JS PHILOSOPHY +These are the high-level design rules which guide the development of Bootstrap's plugin apis. + +--- + +### DATA-ATTRIBUTE API + +We believe you should be able to use all plugins provided by Bootstrap purely through the markup API without writing a single line of javascript. + +We acknowledge that this isn't always the most performant and sometimes it may be desirable to turn this functionality off altogether. Therefore, as of 2.0 we provide the ability to disable the data attribute API by unbinding all events on the body namespaced with `'data-api'`. This looks like this: + + $('body').off('.data-api') + +To target a specific plugin, just include the plugins name as a namespace along with the data-api namespace like this: + + $('body').off('.alert.data-api') + +--- + +### PROGRAMATIC API + +We also believe you should be able to use all plugins provided by Bootstrap purely through the JS API. + +All public APIs should be single, chainable methods, and return the collection acted upon. + + $(".btn.danger").button("toggle").addClass("fat") + +All methods should accept an optional options object, a string which targets a particular method, or null which initiates the default behavior: + + $("#myModal").modal() // initialized with defaults + $("#myModal").modal({ keyboard: false }) // initialized with now keyboard + $("#myModal").modal('show') // initializes and invokes show immediately afterqwe2 + +--- + +### OPTIONS + +Options should be sparse and add universal value. We should pick the right defaults. + +All plugins should have a default object which can be modified to effect all instance's default options. The defaults object should be available via `$.fn.plugin.defaults`. + + $.fn.modal.defaults = { … } + +An options definition should take the following form: + + *noun*: *adjective* - describes or modifies a quality of an instance + +examples: + + backdrop: true + keyboard: false + placement: 'top' + +--- + +### EVENTS + +All events should have an infinitive and past participle form. The infinitive is fired just before an action takes place, the past participle on completion of the action. + + show | shown + hide | hidden + +--- + +### CONSTRUCTORS + +Each plugin should expose it's raw constructor on a `Constructor` property -- accessed in the following way: + + + $.fn.popover.Constructor + +--- + +### DATA ACCESSOR + +Each plugin stores a copy of the invoked class on an object. This class instance can be accessed directly through jQuery's data API like this: + + $('[rel=popover]').data('popover') instanceof $.fn.popover.Constructor + +--- + +### DATA ATTRIBUTES + +Data attributes should take the following form: + +- data-{{verb}}={{plugin}} - defines main interaction +- data-target || href^=# - defined on "control" element (if element controls an element other than self) +- data-{{noun}} - defines class instance options + +examples: + + // control other targets + data-toggle="modal" data-target="#foo" + data-toggle="collapse" data-target="#foo" data-parent="#bar" + + // defined on element they control + data-spy="scroll" + + data-dismiss="modal" + data-dismiss="alert" + + data-toggle="dropdown" + + data-toggle="button" + data-toggle="buttons-checkbox" + data-toggle="buttons-radio" \ No newline at end of file diff --git a/test/public/bootstrap/docs/assets/js/application.js b/test/public/bootstrap/docs/assets/js/application.js new file mode 100644 index 0000000..6463b90 --- /dev/null +++ b/test/public/bootstrap/docs/assets/js/application.js @@ -0,0 +1,184 @@ +// NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT +// IT'S ALL JUST JUNK FOR OUR DOCS! +// ++++++++++++++++++++++++++++++++++++++++++ + +!function ($) { + + $(function(){ + + // Disable certain links in docs + $('section [href^=#]').click(function (e) { + e.preventDefault() + }) + + // make code pretty + window.prettyPrint && prettyPrint() + + // add-ons + $('.add-on :checkbox').on('click', function () { + var $this = $(this) + , method = $this.attr('checked') ? 'addClass' : 'removeClass' + $(this).parents('.add-on')[method]('active') + }) + + // position static twipsies for components page + if ($(".twipsies a").length) { + $(window).on('load resize', function () { + $(".twipsies a").each(function () { + $(this) + .tooltip({ + placement: $(this).attr('title') + , trigger: 'manual' + }) + .tooltip('show') + }) + }) + } + + // add tipsies to grid for scaffolding + if ($('#grid-system').length) { + $('#grid-system').tooltip({ + selector: '.show-grid > div' + , title: function () { return $(this).width() + 'px' } + }) + } + + // fix sub nav on scroll + var $win = $(window) + , $nav = $('.subnav') + , navTop = $('.subnav').length && $('.subnav').offset().top - 40 + , isFixed = 0 + + processScroll() + + // hack sad times - holdover until rewrite for 2.1 + $nav.on('click', function () { + if (!isFixed) setTimeout(function () { $win.scrollTop($win.scrollTop() - 47) }, 10) + }) + + $win.on('scroll', processScroll) + + function processScroll() { + var i, scrollTop = $win.scrollTop() + if (scrollTop >= navTop && !isFixed) { + isFixed = 1 + $nav.addClass('subnav-fixed') + } else if (scrollTop <= navTop && isFixed) { + isFixed = 0 + $nav.removeClass('subnav-fixed') + } + } + + // tooltip demo + $('.tooltip-demo.well').tooltip({ + selector: "a[rel=tooltip]" + }) + + $('.tooltip-test').tooltip() + $('.popover-test').popover() + + // popover demo + $("a[rel=popover]") + .popover() + .click(function(e) { + e.preventDefault() + }) + + // button state demo + $('#fat-btn') + .click(function () { + var btn = $(this) + btn.button('loading') + setTimeout(function () { + btn.button('reset') + }, 3000) + }) + + // carousel demo + $('#myCarousel').carousel() + + // javascript build logic + var inputsComponent = $("#components.download input") + , inputsPlugin = $("#plugins.download input") + , inputsVariables = $("#variables.download input") + + // toggle all plugin checkboxes + $('#components.download .toggle-all').on('click', function (e) { + e.preventDefault() + inputsComponent.attr('checked', !inputsComponent.is(':checked')) + }) + + $('#plugins.download .toggle-all').on('click', function (e) { + e.preventDefault() + inputsPlugin.attr('checked', !inputsPlugin.is(':checked')) + }) + + $('#variables.download .toggle-all').on('click', function (e) { + e.preventDefault() + inputsVariables.val('') + }) + + // request built javascript + $('.download-btn').on('click', function () { + + var css = $("#components.download input:checked") + .map(function () { return this.value }) + .toArray() + , js = $("#plugins.download input:checked") + .map(function () { return this.value }) + .toArray() + , vars = {} + , img = ['glyphicons-halflings.png', 'glyphicons-halflings-white.png'] + + $("#variables.download input") + .each(function () { + $(this).val() && (vars[ $(this).prev().text() ] = $(this).val()) + }) + + $.ajax({ + type: 'POST' + , url: /\?dev/.test(window.location) ? 'http://localhost:3000' : 'http://bootstrap.herokuapp.com' + , dataType: 'jsonpi' + , params: { + js: js + , css: css + , vars: vars + , img: img + } + }) + }) + }) + +// Modified from the original jsonpi https://github.com/benvinegar/jquery-jsonpi +$.ajaxTransport('jsonpi', function(opts, originalOptions, jqXHR) { + var url = opts.url; + + return { + send: function(_, completeCallback) { + var name = 'jQuery_iframe_' + jQuery.now() + , iframe, form + + iframe = $(' + +
  • + +
  • + +
  • + +
  • + +
    + + +
    + +
    +

    Designed for everyone, everywhere.

    + +
    +
    + +

    Built for and by nerds

    +

    Like you, we love building awesome products on the web. We love it so much, we decided to help people just like us do it easier, better, and faster. Bootstrap is built for you.

    +
    +
    + +

    For all skill levels

    +

    Bootstrap is designed to help people of all skill levels—designer or developer, huge nerd or early beginner. Use it as a complete kit or use to start something more complex.

    +
    +
    + +

    Cross-everything

    +

    Originally built with only modern browsers in mind, Bootstrap has evolved to include support for all major browsers (even IE7!) and, with Bootstrap 2, tablets and smartphones, too.

    +
    +
    +
    +
    + +

    12-column grid

    +

    Grid systems aren't everything, but having a durable and flexible one at the core of your work can make development much simpler. Use our built-in grid classes or roll your own.

    +
    +
    + +

    Responsive design

    +

    With Bootstrap 2, we've gone fully responsive. Our components are scaled according to a range of resolutions and devices to provide a consistent experience, no matter what.

    +
    +
    + +

    Styleguide docs

    +

    Unlike other front-end toolkits, Bootstrap was designed first and foremost as a styleguide to document not only our features, but best practices and living, coded examples.

    +
    +
    +
    +
    + +

    Growing library

    +

    Despite being only 10kb (gzipped), Bootstrap is one of the most complete front-end toolkits out there with dozens of fully functional components ready to be put to use.

    +
    +
    + +

    Custom jQuery plugins

    +

    What good is an awesome design component without easy-to-use, proper, and extensible interactions? With Bootstrap, you get custom-built jQuery plugins to bring your projects to life.

    +
    +
    + +

    Built on LESS

    +

    Where vanilla CSS falters, LESS excels. Variables, nesting, operations, and mixins in LESS makes coding CSS faster and more efficient with minimal overhead.

    +
    +
    +
    +
    + +

    HTML5

    +

    Built to support new HTML5 elements and syntax.

    +
    +
    + +

    CSS3

    +

    Progressively enhanced components for ultimate style.

    +
    +
    + +

    Open-source

    +

    Built for and maintained by the community via GitHub.

    +
    +
    + +

    Made at Twitter

    +

    Brought to you by an experienced engineer and designer.

    +
    +
    + +
    + +

    Built with Bootstrap.

    + + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/public/bootstrap/docs/javascript.html b/test/public/bootstrap/docs/javascript.html new file mode 100644 index 0000000..7ad42ae --- /dev/null +++ b/test/public/bootstrap/docs/javascript.html @@ -0,0 +1,1543 @@ + + + + + Javascript · Twitter Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +

    Javascript for Bootstrap

    +

    Bring Bootstrap's components to life—now with 12 custom jQuery plugins. +

    +
    + + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    Heads up! All javascript plugins require the latest version of jQuery.
    +
    + + + + +
    + +
    +
    +

    About modals

    +

    A streamlined, but flexible, take on the traditional javascript modal plugin with only the minimum required functionality and smart defaults.

    + Download file +
    +
    +

    Static example

    +

    Below is a statically rendered modal.

    + + +

    Live demo

    +

    Toggle a modal via javascript by clicking the button below. It will slide down and fade in from the top of the page.

    + + + Launch demo modal + +
    + +

    Using bootstrap-modal

    +

    Call the modal via javascript:

    +
    $('#myModal').modal(options)
    +

    Options

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nametypedefaultdescription
    backdropbooleantrueIncludes a modal-backdrop element. Alternatively, specify static for a backdrop which doesn't close the modal on click.
    keyboardbooleantrueCloses the modal when escape key is pressed
    showbooleantrueShows the modal when initialized.
    +

    Markup

    +

    You can activate modals on your page easily without having to write a single line of javascript. Just set data-toggle="modal" on a controller element with a data-target="#foo" or href="#foo" which corresponds to a modal element id, and when clicked, it will launch your modal.

    +

    Also, to add options to your modal instance, just include them as additional data attributes on either the control element or the modal markup itself.

    +
    +<a class="btn" data-toggle="modal" href="#myModal" >Launch Modal</a>
    +
    + +
    +<div class="modal" id="myModal">
    +  <div class="modal-header">
    +    <button class="close" data-dismiss="modal">×</button>
    +    <h3>Modal header</h3>
    +  </div>
    +  <div class="modal-body">
    +    <p>One fine body…</p>
    +  </div>
    +  <div class="modal-footer">
    +    <a href="#" class="btn">Close</a>
    +    <a href="#" class="btn btn-primary">Save changes</a>
    +  </div>
    +</div>
    +
    +
    + Heads up! If you want your modal to animate in and out, just add a .fade class to the .modal element (refer to the demo to see this in action) and include bootstrap-transition.js. +
    +

    Methods

    +

    .modal(options)

    +

    Activates your content as a modal. Accepts an optional options object.

    +
    +$('#myModal').modal({
    +  keyboard: false
    +})
    +

    .modal('toggle')

    +

    Manually toggles a modal.

    +
    $('#myModal').modal('toggle')
    +

    .modal('show')

    +

    Manually opens a modal.

    +
    $('#myModal').modal('show')
    +

    .modal('hide')

    +

    Manually hides a modal.

    +
    $('#myModal').modal('hide')
    +

    Events

    +

    Bootstrap's modal class exposes a few events for hooking into modal functionality.

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    EventDescription
    showThis event fires immediately when the show instance method is called.
    shownThis event is fired when the modal has been made visible to the user (will wait for css transitions to complete).
    hideThis event is fired immediately when the hide instance method has been called.
    hiddenThis event is fired when the modal has finished being hidden from the user (will wait for css transitions to complete).
    + +
    +$('#myModal').on('hidden', function () {
    +  // do something…
    +})
    +
    +
    +
    + + + + + + + + + +
    + +
    +
    +

    The ScrollSpy plugin is for automatically updating nav targets based on scroll position.

    + Download file +
    +
    +

    Example navbar with scrollspy

    +

    Scroll the area below and watch the navigation update. The dropdown sub items will be highlighted as well. Try it!

    + +
    +

    @fat

    +

    + Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat. +

    +

    @mdo

    +

    + Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard. Freegan beard aliqua cupidatat mcsweeney's vero. Cupidatat four loko nisi, ea helvetica nulla carles. Tattooed cosby sweater food truck, mcsweeney's quis non freegan vinyl. Lo-fi wes anderson +1 sartorial. Carles non aesthetic exercitation quis gentrify. Brooklyn adipisicing craft beer vice keytar deserunt. +

    +

    one

    +

    + Occaecat commodo aliqua delectus. Fap craft beer deserunt skateboard ea. Lomo bicycle rights adipisicing banh mi, velit ea sunt next level locavore single-origin coffee in magna veniam. High life id vinyl, echo park consequat quis aliquip banh mi pitchfork. Vero VHS est adipisicing. Consectetur nisi DIY minim messenger bag. Cred ex in, sustainable delectus consectetur fanny pack iphone. +

    +

    two

    +

    + In incididunt echo park, officia deserunt mcsweeney's proident master cleanse thundercats sapiente veniam. Excepteur VHS elit, proident shoreditch +1 biodiesel laborum craft beer. Single-origin coffee wayfarers irure four loko, cupidatat terry richardson master cleanse. Assumenda you probably haven't heard of them art party fanny pack, tattooed nulla cardigan tempor ad. Proident wolf nesciunt sartorial keffiyeh eu banh mi sustainable. Elit wolf voluptate, lo-fi ea portland before they sold out four loko. Locavore enim nostrud mlkshk brooklyn nesciunt. +

    +

    three

    +

    + Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat. +

    +

    Keytar twee blog, culpa messenger bag marfa whatever delectus food truck. Sapiente synth id assumenda. Locavore sed helvetica cliche irony, thundercats you probably haven't heard of them consequat hoodie gluten-free lo-fi fap aliquip. Labore elit placeat before they sold out, terry richardson proident brunch nesciunt quis cosby sweater pariatur keffiyeh ut helvetica artisan. Cardigan craft beer seitan readymade velit. VHS chambray laboris tempor veniam. Anim mollit minim commodo ullamco thundercats. +

    +
    +
    +

    Using bootstrap-scrollspy.js

    +

    Call the scrollspy via javascript:

    +
    $('#navbar').scrollspy()
    +

    Markup

    +

    To easily add scrollspy behavior to your topbar navigation, just add data-spy="scroll" to the element you want to spy on (most typically this would be the body).

    +
    <body data-spy="scroll" >...</body>
    +
    + Heads up! + Navbar links must have resolvable id targets. For example, a <a href="#home">home</a> must correspond to something in the dom like <div id="home"></div>. +
    +

    Methods

    +

    .scrollspy('refresh')

    +

    When using scrollspy in conjunction with adding or removing of elements from the DOM, you'll need to call the refresh method like so:

    +
    +$('[data-spy="scroll"]').each(function () {
    +  var $spy = $(this).scrollspy('refresh')
    +});
    +
    +

    Options

    + + + + + + + + + + + + + + + + + +
    Nametypedefaultdescription
    offsetnumber10Pixels to offset from top when calculating position of scroll.
    +

    Events

    + + + + + + + + + + + + + +
    EventDescription
    activateThis event fires whenever a new item becomes activated by the scrollspy.
    +
    +
    +
    + + + + +
    + +
    +
    +

    This plugin adds quick, dynamic tab and pill functionality for transitioning through local content.

    + Download file +
    +
    +

    Example tabs

    +

    Click the tabs below to toggle between hidden panes, even via dropdown menus.

    + +
    +
    +

    Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.

    +
    +
    +

    Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.

    +
    + + +
    +
    +

    Using bootstrap-tab.js

    +

    Enable tabbable tabs via javascript (each tab needs to be activated individually):

    +
    +$('#myTab a').click(function (e) {
    +  e.preventDefault();
    +  $(this).tab('show');
    +})
    +

    You can activate individual tabs in several ways:

    +
    +$('#myTab a[href="#profile"]').tab('show'); // Select tab by name
    +$('#myTab a:first').tab('show'); // Select first tab
    +$('#myTab a:last').tab('show'); // Select last tab
    +$('#myTab li:eq(2) a').tab('show'); // Select third tab (0-indexed)
    +
    +

    Markup

    +

    You can activate a tab or pill navigation without writing any javascript by simply specifying data-toggle="tab" or data-toggle="pill" on an element. Adding the nav and nav-tabs classes to the tab ul will apply the bootstrap tab styling.

    +
    +<ul class="nav nav-tabs">
    +  <li><a href="#home" data-toggle="tab">Home</a></li>
    +  <li><a href="#profile" data-toggle="tab">Profile</a></li>
    +  <li><a href="#messages" data-toggle="tab">Messages</a></li>
    +  <li><a href="#settings" data-toggle="tab">Settings</a></li>
    +</ul>
    +

    Methods

    +

    $().tab

    +

    + Activates a tab element and content container. Tab should have either a data-target or an href targeting a container node in the DOM. +

    +
    +<ul class="nav nav-tabs" id="myTab">
    +  <li class="active"><a href="#home">Home</a></li>
    +  <li><a href="#profile">Profile</a></li>
    +  <li><a href="#messages">Messages</a></li>
    +  <li><a href="#settings">Settings</a></li>
    +</ul>
    +
    +<div class="tab-content">
    +  <div class="tab-pane active" id="home">...</div>
    +  <div class="tab-pane" id="profile">...</div>
    +  <div class="tab-pane" id="messages">...</div>
    +  <div class="tab-pane" id="settings">...</div>
    +</div>
    +
    +<script>
    +  $(function () {
    +    $('#myTab a:last').tab('show');
    +  })
    +</script>
    +

    Events

    + + + + + + + + + + + + + + + + + +
    EventDescription
    showThis event fires on tab show, but before the new tab has been shown. Use event.target and event.relatedTarget to target the active tab and the previous active tab (if available) respectively.
    shownThis event fires on tab show after a tab has been shown. Use event.target and event.relatedTarget to target the active tab and the previous active tab (if available) respectively.
    + +
    +$('a[data-toggle="tab"]').on('shown', function (e) {
    +  e.target // activated tab
    +  e.relatedTarget // previous tab
    +})
    +
    +
    +
    + + + +
    + +
    +
    +

    About Tooltips

    +

    Inspired by the excellent jQuery.tipsy plugin written by Jason Frame; Tooltips are an updated version, which don't rely on images, use css3 for animations, and data-attributes for local title storage.

    + Download file +
    +
    +

    Example use of Tooltips

    +

    Hover over the links below to see tooltips:

    +
    +

    Tight pants next level keffiyeh you probably haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel have a terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan whatever keytar, scenester farm-to-table banksy Austin twitter handle freegan cred raw denim single-origin coffee viral. +

    +
    +
    +

    Using bootstrap-tooltip.js

    +

    Trigger the tooltip via javascript:

    +
    $('#example').tooltip(options)
    +

    Options

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nametypedefaultdescription
    animationbooleantrueapply a css fade transition to the tooltip
    placementstring|function'top'how to position the tooltip - top | bottom | left | right
    selectorstringfalseIf a selector is provided, tooltip objects will be delegated to the specified targets.
    titlestring | function''default title value if `title` tag isn't present
    triggerstring'hover'how tooltip is triggered - hover | focus | manual
    delaynumber | object0 +

    delay showing and hiding the tooltip (ms) - does not apply to manual trigger type

    +

    If a number is supplied, delay is applied to both hide/show

    +

    Object structure is: delay: { show: 500, hide: 100 }

    +
    +
    + Heads up! + Options for individual tooltips can alternatively be specified through the use of data attributes. +
    +

    Markup

    +

    For performance reasons, the Tooltip and Popover data-apis are opt in. If you would like to use them just specify a selector option.

    +
    +<a href="#" rel="tooltip" title="first tooltip">hover over me</a>
    +
    +

    Methods

    +

    $().tooltip(options)

    +

    Attaches a tooltip handler to an element collection.

    +

    .tooltip('show')

    +

    Reveals an element's tooltip.

    +
    $('#element').tooltip('show')
    +

    .tooltip('hide')

    +

    Hides an element's tooltip.

    +
    $('#element').tooltip('hide')
    +

    .tooltip('toggle')

    +

    Toggles an element's tooltip.

    +
    $('#element').tooltip('toggle')
    +
    +
    +
    + + + + +
    + +
    +
    +

    About popovers

    +

    Add small overlays of content, like those on the iPad, to any element for housing secondary information.

    +

    * Requires Tooltip to be included

    + Download file +
    +
    +

    Example hover popover

    +

    Hover over the button to trigger the popover.

    + +
    +

    Using bootstrap-popover.js

    +

    Enable popovers via javascript:

    +
    $('#example').popover(options)
    +

    Options

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nametypedefaultdescription
    animationbooleantrueapply a css fade transition to the tooltip
    placementstring|function'right'how to position the popover - top | bottom | left | right
    selectorstringfalseif a selector is provided, tooltip objects will be delegated to the specified targets
    triggerstring'hover'how tooltip is triggered - hover | focus | manual
    titlestring | function''default title value if `title` attribute isn't present
    contentstring | function''default content value if `data-content` attribute isn't present
    delaynumber | object0 +

    delay showing and hiding the popover (ms) - does not apply to manual trigger type

    +

    If a number is supplied, delay is applied to both hide/show

    +

    Object structure is: delay: { show: 500, hide: 100 }

    +
    +
    + Heads up! + Options for individual popovers can alternatively be specified through the use of data attributes. +
    +

    Markup

    +

    + For performance reasons, the Tooltip and Popover data-apis are opt in. If you would like to use them just specify a selector option. +

    +

    Methods

    +

    $().popover(options)

    +

    Initializes popovers for an element collection.

    +

    .popover('show')

    +

    Reveals an elements popover.

    +
    $('#element').popover('show')
    +

    .popover('hide')

    +

    Hides an elements popover.

    +
    $('#element').popover('hide')
    +

    .popover('toggle')

    +

    Toggles an elements popover.

    +
    $('#element').popover('toggle')
    +
    +
    +
    + + + + +
    + +
    +
    +

    About alerts

    +

    The alert plugin is a tiny class for adding close functionality to alerts.

    + Download +
    +
    +

    Example alerts

    +

    The alerts plugin works on regular alert messages, and block messages.

    +
    + + Holy guacamole! Best check yo self, you're not looking too good. +
    +
    + +

    Oh snap! You got an error!

    +

    Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.

    +

    + Take this action Or do this +

    +
    +
    +

    Using bootstrap-alert.js

    +

    Enable dismissal of an alert via javascript:

    +
    $(".alert").alert()
    +

    Markup

    +

    Just add data-dismiss="alert" to your close button to automatically give an alert close functionality.

    +
    <a class="close" data-dismiss="alert" href="#">&times;</a>
    +

    Methods

    +

    $().alert()

    +

    Wraps all alerts with close functionality. To have your alerts animate out when closed, make sure they have the .fade and .in class already applied to them.

    +

    .alert('close')

    +

    Closes an alert.

    +
    $(".alert").alert('close')
    +

    Events

    +

    Bootstrap's alert class exposes a few events for hooking into alert functionality.

    + + + + + + + + + + + + + + + + + +
    EventDescription
    closeThis event fires immediately when the close instance method is called.
    closedThis event is fired when the alert has been closed (will wait for css transitions to complete).
    +
    +$('#my-alert').bind('closed', function () {
    +  // do something…
    +})
    +
    +
    +
    + + + + +
    + +
    +
    +

    About

    +

    Do more with buttons. Control button states or create groups of buttons for more components like toolbars.

    + Download file +
    +
    +

    Example uses

    +

    Use the buttons plugin for states and toggles.

    + + + + + + + + + + + + + + + + + + + +
    Stateful + +
    Single toggle + +
    Checkbox +
    + + + +
    +
    Radio +
    + + + +
    +
    +
    +

    Using bootstrap-button.js

    +

    Enable buttons via javascript:

    +
    $('.nav-tabs').button()
    +

    Markup

    +

    Data attributes are integral to the button plugin. Check out the example code below for the various markup types.

    +
    +<!-- Add data-toggle="button" to activate toggling on a single button -->
    +<button class="btn" data-toggle="button">Single Toggle</button>
    +
    +<!-- Add data-toggle="buttons-checkbox" for checkbox style toggling on btn-group -->
    +<div class="btn-group" data-toggle="buttons-checkbox">
    +  <button class="btn">Left</button>
    +  <button class="btn">Middle</button>
    +  <button class="btn">Right</button>
    +</div>
    +
    +<!-- Add data-toggle="buttons-radio" for radio style toggling on btn-group -->
    +<div class="btn-group" data-toggle="buttons-radio">
    +  <button class="btn">Left</button>
    +  <button class="btn">Middle</button>
    +  <button class="btn">Right</button>
    +</div>
    +
    +

    Methods

    +

    $().button('toggle')

    +

    Toggles push state. Gives the button the appearance that it has been activated.

    +
    + Heads up! + You can enable auto toggling of a button by using the data-toggle attribute. +
    +
    <button class="btn" data-toggle="button" >…</button>
    +

    $().button('loading')

    +

    Sets button state to loading - disables button and swaps text to loading text. Loading text should be defined on the button element using the data attribute data-loading-text. +

    +
    <button class="btn" data-loading-text="loading stuff..." >...</button>
    +
    + Heads up! + Firefox persists the disabled state across page loads. A workaround for this is to use autocomplete="off". +
    +

    $().button('reset')

    +

    Resets button state - swaps text to original text.

    +

    $().button(string)

    +

    Resets button state - swaps text to any data defined text state.

    +
    <button class="btn" data-complete-text="finished!" >...</button>
    +<script>
    +  $('.btn').button('complete')
    +</script>
    +
    +
    +
    + + + + +
    + +
    +
    +

    About

    +

    Get base styles and flexible support for collapsible components like accordions and navigation.

    + Download file +

    * Requires the Transitions plugin to be included.

    +
    +
    +

    Example accordion

    +

    Using the collapse plugin, we built a simple accordion style widget:

    + +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + + +
    +

    Using bootstrap-collapse.js

    +

    Enable via javascript:

    +
    $(".collapse").collapse()
    +

    Options

    + + + + + + + + + + + + + + + + + + + + + + + +
    Nametypedefaultdescription
    parentselectorfalseIf selector then all collapsible elements under the specified parent will be closed when this collapsible item is shown. (similar to traditional accordion behavior)
    togglebooleantrueToggles the collapsible element on invocation
    +

    Markup

    +

    Just add data-toggle="collapse" and a data-target to element to automatically assign control of a collapsible element. The data-target attribute accepts a css selector to apply the collapse to. Be sure to add the class collapse to the collapsible element. If you'd like it to default open, add the additional class in.

    +
    +<button class="btn btn-danger" data-toggle="collapse" data-target="#demo">
    +  simple collapsible
    +</button>
    +
    +<div id="demo" class="collapse in"> … </div>
    +
    + Heads up! + To add accordion-like group management to a collapsible control, add the data attribute data-parent="#selector". Refer to the demo to see this in action. +
    +

    Methods

    +

    .collapse(options)

    +

    Activates your content as a collapsible element. Accepts an optional options object. +

    +$('#myCollapsible').collapse({
    +  toggle: false
    +})
    +

    .collapse('toggle')

    +

    Toggles a collapsible element to shown or hidden.

    +

    .collapse('show')

    +

    Shows a collapsible element.

    +

    .collapse('hide')

    +

    Hides a collapsible element.

    +

    Events

    +

    + Bootstrap's collapse class exposes a few events for hooking into collapse functionality. +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    EventDescription
    showThis event fires immediately when the show instance method is called.
    shownThis event is fired when a collapse element has been made visible to the user (will wait for css transitions to complete).
    hide + This event is fired immediately when the hide method has been called. +
    hiddenThis event is fired when a collapse element has been hidden from the user (will wait for css transitions to complete).
    + +
    +$('#myCollapsible').on('hidden', function () {
    +  // do something…
    +})
    +
    +
    +
    + + + + + + + + + +
    + +
    +
    +

    About

    +

    A basic, easily extended plugin for quickly creating elegant typeaheads with any form text input.

    + Download file +
    +
    +

    Example

    +

    Start typing in the field below to show the typeahead results.

    +
    + +
    +
    +

    Using bootstrap-typeahead.js

    +

    Call the typeahead via javascript:

    +
    $('.typeahead').typeahead()
    +

    Options

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Nametypedefaultdescription
    sourcearray[ ]The data source to query against.
    itemsnumber8The max number of items to display in the dropdown.
    matcherfunctioncase insensitiveThe method used to determine if a query matches an item. Accepts a single argument, the item against which to test the query. Access the current query with this.query. Return a boolean true if query is a match.
    sorterfunctionexact match,
    case sensitive,
    case insensitive
    Method used to sort autocomplete results. Accepts a single argument items and has the scope of the typeahead instance. Reference the current query with this.query.
    highlighterfunctionhighlights all default matchesMethod used to highlight autocomplete results. Accepts a single argument item and has the scope of the typeahead instance. Should return html.
    + +

    Markup

    +

    Add data attributes to register an element with typeahead functionality.

    +
    +<input type="text" data-provide="typeahead">
    +
    +

    Methods

    +

    .typeahead(options)

    +

    Initializes an input with a typeahead.

    +
    +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/public/bootstrap/docs/less.html b/test/public/bootstrap/docs/less.html new file mode 100644 index 0000000..3fecd1a --- /dev/null +++ b/test/public/bootstrap/docs/less.html @@ -0,0 +1,1053 @@ + + + + + Less · Twitter Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +

    Using LESS with Bootstrap

    +

    Customize and extend Bootstrap with LESS, a CSS preprocessor, to take advantage of the variables, mixins, and more used to build Bootstrap's CSS.

    + +
    + + + + +
    + +
    +
    +

    Why LESS?

    +

    Bootstrap is made with LESS at its core, a dynamic stylesheet language created by our good friend, Alexis Sellier. It makes developing systems-based CSS faster, easier, and more fun.

    +
    +
    +

    What's included?

    +

    As an extension of CSS, LESS includes variables, mixins for reusable snippets of code, operations for simple math, nesting, and even color functions.

    +
    +
    +

    Learn more

    + LESS CSS +

    Visit the official website at http://lesscss.org to learn more.

    +
    +
    +
    +
    +

    Variables

    +

    Managing colors and pixel values in CSS can be a bit of a pain, usually full of copy and paste. Not with LESS though—assign colors or pixel values as variables and change them once.

    +
    +
    +

    Mixins

    +

    Those three border-radius declarations you need to make in regular ol' CSS? Now they're down to one line with the help of mixins, snippets of code you can reuse anywhere.

    +
    +
    +

    Operations

    +

    Make your grid, leading, and more super flexible by doing the math on the fly with operations. Multiply, divide, add, and subtract your way to CSS sanity.

    +
    +
    +
    + + + + +
    + + +
    +
    +

    Scaffolding and links

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @bodyBackground@whitePage background color
    @textColor@grayDarkDefault text color for entire body, headings, and more
    @linkColor#08cDefault link text color
    @linkColorHoverdarken(@linkColor, 15%)Default link text hover color
    +

    Grid system

    + + + + + + + + + + + + + + + + + + + + + + + +
    @gridColumns12
    @gridColumnWidth60px
    @gridGutterWidth20px
    @fluidGridColumnWidth6.382978723%
    @fluidGridGutterWidth2.127659574%
    +

    Typography

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @sansFontFamily"Helvetica Neue", Helvetica, Arial, sans-serif
    @serifFontFamilyGeorgia, "Times New Roman", Times, serif
    @monoFontFamilyMenlo, Monaco, "Courier New", monospace
    @baseFontSize13pxMust be pixels
    @baseFontFamily@sansFontFamily
    @baseLineHeight18pxMust be pixels
    @altFontFamily@serifFontFamily
    @headingsFontFamilyinherit
    @headingsFontWeightbold
    @headingsColorinherit
    +

    Tables

    + + + + + + + + + + + + + + + + + + + +
    @tableBackgroundtransparent
    @tableBackgroundAccent#f9f9f9
    @tableBackgroundHover#f5f5f5
    @tableBorderddd
    +
    +
    +

    Grayscale colors

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @black#000
    @grayDarker#222
    @grayDark#333
    @gray#555
    @grayLight#999
    @grayLighter#eee
    @white#fff
    +

    Accent colors

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @blue#049cdb
    @green#46a546
    @red#9d261d
    @yellow#ffc40d
    @orange#f89406
    @pink#c3325f
    @purple#7a43b6
    +
    +
    + +

    Components

    +
    +
    +

    Buttons

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @btnBackground@white
    @btnBackgroundHighlightdarken(@white, 10%)
    @btnBorderdarken(@white, 20%)
    @btnPrimaryBackground@linkColor
    @btnPrimaryBackgroundHighlightspin(@btnPrimaryBackground, 15%)
    @btnInfoBackground#5bc0de
    @btnInfoBackgroundHighlight#2f96b4
    @btnSuccessBackground#62c462
    @btnSuccessBackgroundHighlight51a351
    @btnWarningBackgroundlighten(@orange, 15%)
    @btnWarningBackgroundHighlight@orange
    @btnDangerBackground#ee5f5b
    @btnDangerBackgroundHighlight#bd362f
    @btnInverseBackground@gray
    @btnInverseBackgroundHighlight@grayDarker
    +

    Forms

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @placeholderText@grayLight
    @inputBackground@white
    @inputBorder#ccc
    @inputBorderRadius3px
    @inputDisabledBackground@grayLighter
    @formActionsBackground#f5f5f5
    +

    Form states and alerts

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @warningText#c09853
    @warningBackground#f3edd2
    @errorText#b94a48
    @errorBackground#f2dede
    @successText#468847
    @successBackground#dff0d8
    @infoText#3a87ad
    @infoBackground#d9edf7
    +
    +
    +

    Navbar

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @navbarHeight40px
    @navbarBackground@grayDarker
    @navbarBackgroundHighlight@grayDark
    @navbarText@grayLight
    @navbarLinkColor@grayLight
    @navbarLinkColorHover@white
    @navbarLinkColorActive@navbarLinkColorHover
    @navbarLinkBackgroundHovertransparent
    @navbarLinkBackgroundActive@navbarBackground
    @navbarSearchBackgroundlighten(@navbarBackground, 25%)
    @navbarSearchBackgroundFocus@white
    @navbarSearchBorderdarken(@navbarSearchBackground, 30%)
    @navbarSearchPlaceholderColor#ccc
    @navbarBrandColor@navbarLinkColor
    +

    Dropdowns

    + + + + + + + + + + + + + + + + + + + + + + + +
    @dropdownBackground@white
    @dropdownBorderrgba(0,0,0,.2)
    @dropdownLinkColor@grayDark
    @dropdownLinkColorHover@white
    @dropdownLinkBackgroundHover@linkColor
    +

    Hero unit

    + + + + + + + + + + + + + + + + + + +
    @heroUnitBackground@grayLighter
    @heroUnitHeadingColorinherit
    @heroUnitLeadColorinhereit
    +
    +
    + +
    + + + + +
    + +

    About mixins

    +
    +
    +

    Basic mixins

    +

    A basic mixin is essentially an include or a partial for a snippet of CSS. They're written just like a CSS class and can be called anywhere.

    +
    +.element {
    +  .clearfix();
    +}
    +
    +
    +
    +

    Parametric mixins

    +

    A parametric mixin is just like a basic mixin, but it also accepts parameters (hence the name) with optional default values.

    +
    +.element {
    +  .border-radius(4px);
    +}
    +
    +
    +
    +

    Easily add your own

    +

    Nearly all of Bootstrap's mixins are stored in mixins.less, a wonderful utility .less file that enables you to use a mixin in any of the .less files in the toolkit.

    +

    So, go ahead and use the existing ones or feel free to add your own as you need.

    +
    +
    +

    Included mixins

    +

    Utilities

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MixinParametersUsage
    .clearfix()noneAdd to any parent to clear floats within
    .tab-focus()noneApply the Webkit focus style and round Firefox outline
    .center-block()noneAuto center a block-level element using margin: auto
    .ie7-inline-block()noneUse in addition to regular display: inline-block to get IE7 support
    .size()@height @widthQuickly set the height and width on one line
    .square()@sizeBuilds on .size() to set the width and height as same value
    .opacity()@opacitySet, in whole numbers, the opacity percentage (e.g., "50" or "75")
    +

    Forms

    + + + + + + + + + + + + + + + +
    MixinParametersUsage
    .placeholder()@color: @placeholderTextSet the placeholder text color for inputs
    +

    Typography

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MixinParametersUsage
    #font > #family > .serif()noneMake an element use a serif font stack
    #font > #family > .sans-serif()noneMake an element use a sans-serif font stack
    #font > #family > .monospace()noneMake an element use a monospace font stack
    #font > .shorthand()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeightEasily set font size, weight, and leading
    #font > .serif()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeightSet font family to serif, and control size, weight, and leading
    #font > .sans-serif()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeightSet font family to sans-serif, and control size, weight, and leading
    #font > .monospace()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeightSet font family to monospace, and control size, weight, and leading
    +

    Grid system

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MixinParametersUsage
    .container-fixed()noneCreate a horizontally centered container for holding your content
    #grid > .core()@gridColumnWidth, @gridGutterWidthGenerate a pixel grid system (container, row, and columns) with n columns and x pixel wide gutter
    #grid > .fluid()@fluidGridColumnWidth, @fluidGridGutterWidthGenerate a precent grid system with n columns and x % wide gutter
    #grid > .input()@gridColumnWidth, @gridGutterWidthGenerate the pixel grid system for input elements, accounting for padding and borders
    .makeColumn@columns: 1, @offset: 0Turn any div into a grid column without the .span* classes
    +

    CSS3 properties

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MixinParametersUsage
    .border-radius()@radiusRound the corners of an element. Can be a single value or four space-separated values
    .box-shadow()@shadowAdd a drop shadow to an element
    .transition()@transitionAdd CSS3 transition effect (e.g., all .2s linear)
    .rotate()@degreesRotate an element n degrees
    .scale()@ratioScale an element to n times its original size
    .translate()@x, @yMove an element on the x and y planes
    .background-clip()@clipCrop the background of an element (useful for border-radius)
    .background-size()@sizeControl the size of background images via CSS3
    .box-sizing()@boxmodelChange the box model for an element (e.g., border-box for a full-width input)
    .user-select()@selectControl cursor selection of text on a page
    .backface-visibility()@visibility: visiblePrevent flickering of content when using CSS 3D transforms
    .resizable()@direction: bothMake any element resizable on the right and bottom
    .content-columns()@columnCount, @columnGap: @gridGutterWidthMake the content of any element use CSS3 columns
    +

    Backgrounds and gradients

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MixinParametersUsage
    #translucent > .background()@color: @white, @alpha: 1Give an element a translucent background color
    #translucent > .border()@color: @white, @alpha: 1Give an element a translucent border color
    #gradient > .vertical()@startColor, @endColorCreate a cross-browser vertical background gradient
    #gradient > .horizontal()@startColor, @endColorCreate a cross-browser horizontal background gradient
    #gradient > .directional()@startColor, @endColor, @degCreate a cross-browser directional background gradient
    #gradient > .vertical-three-colors()@startColor, @midColor, @colorStop, @endColorCreate a cross-browser three-color background gradient
    #gradient > .radial()@innerColor, @outerColorCreate a cross-browser radial background gradient
    #gradient > .striped()@color, @angleCreate a cross-browser striped background gradient
    #gradientBar()@primaryColor, @secondaryColorUsed for buttons to assign a gradient and slightly darker border
    +
    + + + + +
    + +
    + Note: If you're submitting a pull request to GitHub with modified CSS, you must recompile the CSS via any of these methods. +
    +

    Tools for compiling

    +
    +
    +

    Node with makefile

    +

    Install the LESS command line compiler and uglify-js globally with npm by running the following command:

    +
    $ npm install -g less uglify-js
    +

    Once installed just run make from the root of your bootstrap directory and you're all set.

    +

    Additionally, if you have watchr installed, you may run make watch to have bootstrap automatically rebuilt every time you edit a file in the bootstrap lib (this isn't required, just a convenience method).

    +
    +
    +

    Command line

    +

    Install the LESS command line tool via Node and run the following command:

    +
    $ lessc ./less/bootstrap.less > bootstrap.css
    +

    Be sure to include --compress in that command if you're trying to save some bytes!

    +
    +
    +

    Javascript

    +

    Download the latest Less.js and include the path to it (and Bootstrap) in the <head>.

    +
    +<link rel="stylesheet/less" href="/path/to/bootstrap.less">
    +<script src="/path/to/less.js"></script>
    +
    +

    To recompile the .less files, just save them and reload your page. Less.js compiles them and stores them in local storage.

    +
    +
    +
    +
    +

    Unofficial Mac app

    +

    The unofficial Mac app watches directories of .less files and compiles the code to local files after every save of a watched .less file.

    +

    If you like, you can toggle preferences in the app for automatic minifying and which directory the compiled files end up in.

    +
    +
    +

    More Mac apps

    +

    Crunch

    +

    Crunch is a great looking LESS editor and compiler built on Adobe Air.

    +

    CodeKit

    +

    Created by the same guy as the unofficial Mac app, CodeKit is a Mac app that compiles LESS, SASS, Stylus, and CoffeeScript.

    +

    Simpless

    +

    Mac, Linux, and PC app for drag and drop compiling of LESS files. Plus, the source code is on GitHub.

    +
    +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/public/bootstrap/docs/scaffolding.html b/test/public/bootstrap/docs/scaffolding.html new file mode 100644 index 0000000..caffa6a --- /dev/null +++ b/test/public/bootstrap/docs/scaffolding.html @@ -0,0 +1,671 @@ + + + + + Scaffolding · Twitter Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +

    Scaffolding

    +

    Bootstrap is built on a responsive 12-column grid. We've also included fixed- and fluid-width layouts based on that system.

    + +
    + + + + + +
    + +
    +
    +

    Requires HTML5 doctype

    +

    Bootstrap makes use of HTML elements and CSS properties that require the use of the HTML5 doctype. Be sure to include it at the beginning of every Bootstrapped page in your project.

    +
    +<!DOCTYPE html>
    +<html lang="en">
    +  ...
    +</html>
    +
    +
    +
    +

    Typography and links

    +

    Within the scaffolding.less file, we set basic global display, typography, and link styles. Specifically, we:

    +
      +
    • Remove margin on the body
    • +
    • Set background-color: white; on the body
    • +
    • Use the @baseFontFamily, @baseFontSize, and @baseLineHeight attributes as our typographyic base
    • +
    • Set the global link color via @linkColor and apply link underlines only on :hover
    • +
    +
    +
    +

    Reset via Normalize

    +

    As of Bootstrap 2, the traditional CSS reset has evolved to make use of elements from Normalize.css, a project by Nicolas Gallagher that also powers the HTML5 Boilerplate.

    +

    The new reset can still be found in reset.less, but with many elements removed for brevity and accuracy.

    +
    +
    +
    + + + + + +
    + + +
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    +
    +
    4
    +
    4
    +
    4
    +
    +
    +
    4
    +
    8
    +
    +
    +
    6
    +
    6
    +
    +
    +
    12
    +
    +
    +
    +

    The default grid system provided as part of Bootstrap is a 940px-wide, 12-column grid.

    +

    It also has four responsive variations for various devices and resolutions: phone, tablet portrait, tablet landscape and small desktops, and large widescreen desktops.

    +
    +
    +
    +<div class="row">
    +  <div class="span4">...</div>
    +  <div class="span8">...</div>
    +</div>
    +
    +
    +
    +

    As shown here, a basic layout can be created with two "columns", each spanning a number of the 12 foundational columns we defined as part of our grid system.

    +
    +
    + +
    + +

    Offsetting columns

    +
    +
    4
    +
    4 offset 4
    +
    +
    +
    3 offset 3
    +
    3 offset 3
    +
    +
    +
    8 offset 4
    +
    +
    +<div class="row">
    +  <div class="span4">...</div>
    +  <div class="span4 offset4">...</div>
    +</div>
    +
    + +
    + +

    Nesting columns

    +
    +
    +

    With the static (non-fluid) grid system in Bootstrap, nesting is easy. To nest your content, just add a new .row and set of .span* columns within an existing .span* column.

    +

    Example

    +

    Nested rows should include a set of columns that add up to the number of columns of it's parent. For example, two nested .span3 columns should be placed within a .span6.

    +
    +
    + Level 1 of column +
    +
    + Level 2 +
    +
    + Level 2 +
    +
    +
    +
    +
    +
    +
    +<div class="row">
    +  <div class="span12">
    +    Level 1 of column
    +    <div class="row">
    +      <div class="span6">Level 2</div>
    +      <div class="span6">Level 2</div>
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    +
    + + + + +
    + + +

    Fluid columns

    +
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    +
    +
    4
    +
    4
    +
    4
    +
    +
    +
    4
    +
    8
    +
    +
    +
    6
    +
    6
    +
    +
    +
    12
    +
    + +
    +
    +

    Percents, not pixels

    +

    The fluid grid system uses percents for column widths instead of fixed pixels. It also has the same responsive variations as our fixed grid system, ensuring proper proportions for key screen resolutions and devices.

    +
    +
    +

    Fluid rows

    +

    Make any row fluid simply by changing .row to .row-fluid. The columns stay the exact same, making it super straightforward to flip between fixed and fluid layouts.

    +
    +
    +

    Markup

    +
    +<div class="row-fluid">
    +  <div class="span4">...</div>
    +  <div class="span8">...</div>
    +</div>
    +
    +
    +
    + +

    Fluid nesting

    +
    +
    +

    Nesting with fluid grids is a bit different: the number of nested columns doesn't need to match the parent. Instead, your columns are reset at each level because each row takes up 100% of the parent column.

    +
    +
    + Fluid 12 +
    +
    + Fluid 6 +
    +
    + Fluid 6 +
    +
    +
    +
    +
    +
    +
    +<div class="row-fluid">
    +  <div class="span12">
    +    Level 1 of column
    +    <div class="row-fluid">
    +      <div class="span6">Level 2</div>
    +      <div class="span6">Level 2</div>
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VariableDefault valueDescription
    @gridColumns12Number of columns
    @gridColumnWidth60pxWidth of each column
    @gridGutterWidth20pxNegative space between columns
    +
    +
    +

    Variables in LESS

    +

    Built into Bootstrap are a handful of variables for customizing the default 940px grid system, documented above. All variables for the grid are stored in variables.less.

    +
    +
    +

    How to customize

    +

    Modifying the grid means changing the three @grid* variables and recompiling Bootstrap. Change the grid variables in variables.less and use one of the four ways documented to recompile. If you're adding more columns, be sure to add the CSS for those in grid.less.

    +
    +
    +

    Staying responsive

    +

    Customization of the grid only works at the default level, the 940px grid. To maintain the responsive aspects of Bootstrap, you'll also have to customize the grids in responsive.less.

    +
    +
    + +
    + + + + +
    + + +
    +
    +

    Fixed layout

    +

    The default and simple 940px-wide, centered layout for just about any website or page provided by a single <div class="container">.

    +
    +
    +
    +
    +<body>
    +  <div class="container">
    +    ...
    +  </div>
    +</body>
    +
    +
    +
    +

    Fluid layout

    +

    <div class="container-fluid"> gives flexible page structure, min- and max-widths, and a left-hand sidebar. It's great for apps and docs.

    +
    +
    +
    +
    +
    +<div class="container-fluid">
    +  <div class="row-fluid">
    +    <div class="span2">
    +      <!--Sidebar content-->
    +    </div>
    +    <div class="span10">
    +      <!--Body content-->
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    +
    + + + + + +
    + + +
    +
    +

    Responsive devices

    +

    What they do

    +

    Media queries allow for custom CSS based on a number of conditions—ratios, widths, display type, etc—but usually focuses around min-width and max-width.

    +
      +
    • Modify the width of column in our grid
    • +
    • Stack elements instead of float wherever necessary
    • +
    • Resize headings and text to be more appropriate for devices
    • +
    +

    Use media queries responsibly and only as a start to your mobile audiences. For larger projects, do consider dedicated code bases and not layers of media queries.

    +
    +
    +

    Supported devices

    +

    Bootstrap supports a handful of media queries in a single file to help make your projects more appropriate on different devices and screen resolutions. Here's what's included:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LabelLayout widthColumn widthGutter width
    Smartphones480px and belowFluid columns, no fixed widths
    Smartphones to tablets767px and belowFluid columns, no fixed widths
    Portrait tablets768px and above42px20px
    Default980px and up60px20px
    Large display1200px and up70px30px
    + +

    Requires meta tag

    +

    To ensure devices display responsive pages properly, include the viewport meta tag.

    +
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    +
    +
    + +
    + + +

    Using the media queries

    +
    +
    +

    Bootstrap doesn't automatically include these media queries, but understanding and adding them is very easy and requires minimal setup. You have a few options for including the responsive features of Bootstrap:

    +
      +
    1. Use the compiled responsive version, bootstrap-responsive.css
    2. +
    3. Add @import "responsive.less" and recompile Bootstrap
    4. +
    5. Modify and recompile responsive.less as a separate file
    6. +
    +

    Why not just include it? Truth be told, not everything needs to be responsive. Instead of encouraging developers to remove this feature, we figure it best to enable it.

    +
    +
    +
    +  // Landscape phones and down
    +  @media (max-width: 480px) { ... }
    +
    +  // Landscape phone to portrait tablet
    +  @media (max-width: 767px) { ... }
    +
    +  // Portrait tablet to landscape and desktop
    +  @media (min-width: 768px) and (max-width: 979px) { ... }
    +
    +  // Large desktop
    +  @media (min-width: 1200px) { ... }
    +
    +
    +
    +
    + + +

    Responsive utility classes

    +
    +
    +

    What are they

    +

    For faster mobile-friendly development, use these basic utility classes for showing and hiding content by device.

    +

    When to use

    +

    Use on a limited basis and avoid creating entirely different versions of the same site. Instead, use them to complement each device's presentation.

    +

    For example, you might show a <select> element for nav on mobile layouts, but not on tablets or desktops.

    +
    +
    +

    Support classes

    +

    Shown here is a table of the classes we support and their effect on a given media query layout (labeled by device). They can be found in responsive.less.

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ClassPhones 480px and belowTablets 767px and belowDesktops 768px and above
    .visible-phoneVisible
    .visible-tabletVisible
    .visible-desktopVisible
    .hidden-phoneVisibleVisible
    .hidden-tabletVisibleVisible
    .hidden-desktopVisibleVisible
    +

    Test case

    +

    Resize your browser or load on different devices to test the above classes.

    +

    Visible on...

    +

    Green checkmarks indicate that class is visible in your current viewport.

    +
      +
    • Phone✔ Phone
    • +
    • Tablet✔ Tablet
    • +
    • Desktop✔ Desktop
    • +
    +

    Hidden on...

    +

    Here, green checkmarks indicate that class is hidden in your current viewport.

    +
      +
    • Phone✔ Phone
    • +
    • Tablet✔ Tablet
    • +
    • Desktop✔ Desktop
    • +
    +
    +
    + + +
    +
    +
    +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/public/bootstrap/docs/templates/layout.mustache b/test/public/bootstrap/docs/templates/layout.mustache new file mode 100644 index 0000000..4fdaadb --- /dev/null +++ b/test/public/bootstrap/docs/templates/layout.mustache @@ -0,0 +1,133 @@ + + + + + {{title}} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +{{>body}} + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + {{#production}} + + + {{/production}} + + + diff --git a/test/public/bootstrap/docs/templates/pages/base-css.mustache b/test/public/bootstrap/docs/templates/pages/base-css.mustache new file mode 100644 index 0000000..3524ac9 --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/base-css.mustache @@ -0,0 +1,1592 @@ + +
    +

    {{_i}}Base CSS{{/i}}

    +

    {{_i}}On top of the scaffolding, basic HTML elements are styled and enhanced with extensible classes to provide a fresh, consistent look and feel.{{/i}}

    + +
    + + + +
    + + +

    {{_i}}Headings & body copy{{/i}}

    + + +
    +
    +

    {{_i}}Typographic scale{{/i}}

    +

    {{_i}}The entire typographic grid is based on two Less variables in our variables.less file: @baseFontSize and @baseLineHeight. The first is the base font-size used throughout and the second is the base line-height.{{/i}}

    +

    {{_i}}We use those variables, and some math, to create the margins, paddings, and line-heights of all our type and more.{{/i}}

    +
    +
    +

    {{_i}}Example body text{{/i}}

    +

    Nullam quis risus eget urna mollis ornare vel eu leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam id dolor id nibh ultricies vehicula ut id elit.

    +

    Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec sed odio dui.

    +
    +
    +
    +

    h1. {{_i}}Heading 1{{/i}}

    +

    h2. {{_i}}Heading 2{{/i}}

    +

    h3. {{_i}}Heading 3{{/i}}

    +

    h4. {{_i}}Heading 4{{/i}}

    +
    h5. {{_i}}Heading 5{{/i}}
    +
    h6. {{_i}}Heading 6{{/i}}
    +
    +
    +
    + + +

    {{_i}}Emphasis, address, and abbreviation{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Element{{/i}}{{_i}}Usage{{/i}}{{_i}}Optional{{/i}}
    + <strong> + + {{_i}}For emphasizing a snippet of text with important{{/i}} + + {{_i}}None{{/i}} +
    + <em> + + {{_i}}For emphasizing a snippet of text with stress{{/i}} + + {{_i}}None{{/i}} +
    + <abbr> + + {{_i}}Wraps abbreviations and acronyms to show the expanded version on hover{{/i}} + +

    {{_i}}Include optional title attribute for expanded text{{/i}}

    + {{_i}}Use .initialism class for uppercase abbreviations.{{/i}} +
    + <address> + + {{_i}}For contact information for its nearest ancestor or the entire body of work{{/i}} + + {{_i}}Preserve formatting by ending all lines with <br>{{/i}} +
    + +
    +
    +

    {{_i}}Using emphasis{{/i}}

    +

    Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Maecenas faucibus mollis interdum. Nulla vitae elit libero, a pharetra augue.

    +

    {{_i}}Note: Feel free to use <b> and <i> in HTML5, but their usage has changed a bit. <b> is meant to highlight words or phrases without conveying additional importance while <i> is mostly for voice, technical terms, etc.{{/i}}

    +
    +
    +

    {{_i}}Example addresses{{/i}}

    +

    {{_i}}Here are two examples of how the <address> tag can be used:{{/i}}

    +
    + Twitter, Inc.
    + 795 Folsom Ave, Suite 600
    + San Francisco, CA 94107
    + P: (123) 456-7890 +
    +
    + {{_i}}Full Name{{/i}}
    + {{_i}}first.last@gmail.com{{/i}} +
    +
    +
    +

    {{_i}}Example abbreviations{{/i}}

    +

    {{_i}}Abbreviations with a title attribute have a light dotted bottom border and a help cursor on hover. This gives users extra indication something will be shown on hover.{{/i}}

    +

    {{_i}}Add the initialism class to an abbreviation to increase typographic harmony by giving it a slightly smaller text size.{{/i}}

    +

    {{_i}}HTML is the best thing since sliced bread.{{/i}}

    +

    {{_i}}An abbreviation of the word attribute is attr.{{/i}}

    +
    +
    + + + +

    {{_i}}Blockquotes{{/i}}

    + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Element{{/i}}{{_i}}Usage{{/i}}{{_i}}Optional{{/i}}
    + <blockquote> + + {{_i}}Block-level element for quoting content from another source{{/i}} + +

    {{_i}}Add cite attribute for source URL{{/i}}

    + {{_i}}Use .pull-left and .pull-right classes for floated options{{/i}} +
    + <small> + + {{_i}}Optional element for adding a user-facing citation, typically an author with title of work{{/i}} + + {{_i}}Place the <cite> around the title or name of source{{/i}} +
    +
    +
    +

    {{_i}}To include a blockquote, wrap <blockquote> around any HTML as the quote. For straight quotes we recommend a <p>.{{/i}}

    +

    {{_i}}Include an optional <small> element to cite your source and you'll get an em dash &mdash; before it for styling purposes.{{/i}}

    +
    +
    +
    +<blockquote>
    +  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante venenatis.</p>
    +  <small>{{_i}}Someone famous{{/i}}</small>
    +</blockquote>
    +
    +
    +
    + +

    {{_i}}Example blockquotes{{/i}}

    +
    +
    +

    {{_i}}Default blockquotes are styled as such:{{/i}}

    +
    +

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante venenatis.

    + {{_i}}Someone famous in Body of work{{/i}} +
    +
    +
    +

    {{_i}}To float your blockquote to the right, add class="pull-right":{{/i}}

    +
    +

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante venenatis.

    + {{_i}}Someone famous in Body of work{{/i}} +
    +
    +
    + + + +

    {{_i}}Lists{{/i}}

    +
    +
    +

    {{_i}}Unordered{{/i}}

    +

    <ul>

    +
      +
    • Lorem ipsum dolor sit amet
    • +
    • Consectetur adipiscing elit
    • +
    • Integer molestie lorem at massa
    • +
    • Facilisis in pretium nisl aliquet
    • +
    • Nulla volutpat aliquam velit +
        +
      • Phasellus iaculis neque
      • +
      • Purus sodales ultricies
      • +
      • Vestibulum laoreet porttitor sem
      • +
      • Ac tristique libero volutpat at
      • +
      +
    • +
    • Faucibus porta lacus fringilla vel
    • +
    • Aenean sit amet erat nunc
    • +
    • Eget porttitor lorem
    • +
    +
    +
    +

    {{_i}}Unstyled{{/i}}

    +

    <ul class="unstyled">

    +
      +
    • Lorem ipsum dolor sit amet
    • +
    • Consectetur adipiscing elit
    • +
    • Integer molestie lorem at massa
    • +
    • Facilisis in pretium nisl aliquet
    • +
    • Nulla volutpat aliquam velit +
        +
      • Phasellus iaculis neque
      • +
      • Purus sodales ultricies
      • +
      • Vestibulum laoreet porttitor sem
      • +
      • Ac tristique libero volutpat at
      • +
      +
    • +
    • Faucibus porta lacus fringilla vel
    • +
    • Aenean sit amet erat nunc
    • +
    • Eget porttitor lorem
    • +
    +
    +
    +

    {{_i}}Ordered{{/i}}

    +

    <ol>

    +
      +
    1. Lorem ipsum dolor sit amet
    2. +
    3. Consectetur adipiscing elit
    4. +
    5. Integer molestie lorem at massa
    6. +
    7. Facilisis in pretium nisl aliquet
    8. +
    9. Nulla volutpat aliquam velit
    10. +
    11. Faucibus porta lacus fringilla vel
    12. +
    13. Aenean sit amet erat nunc
    14. +
    15. Eget porttitor lorem
    16. +
    +
    +
    +
    +
    +
    +

    {{_i}}Description{{/i}}

    +

    <dl>

    +
    +
    {{_i}}Description lists{{/i}}
    +
    {{_i}}A description list is perfect for defining terms.{{/i}}
    +
    Euismod
    +
    Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.
    +
    Donec id elit non mi porta gravida at eget metus.
    +
    Malesuada porta
    +
    Etiam porta sem malesuada magna mollis euismod.
    +
    +
    +
    +

    {{_i}}Horizontal description{{/i}}

    +

    <dl class="dl-horizontal">

    +
    +
    {{_i}}Description lists{{/i}}
    +
    {{_i}}A description list is perfect for defining terms.{{/i}}
    +
    Euismod
    +
    Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.
    +
    Donec id elit non mi porta gravida at eget metus.
    +
    Malesuada porta
    +
    Etiam porta sem malesuada magna mollis euismod.
    +
    Felis euismod semper eget lacinia
    +
    Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.
    +
    +
    +

    + {{_i}}Heads up!{{/i}} + {{_i}}Horizontal description lists will truncate terms that are too long to fit in the left column fix text-overflow. In narrower viewports, they will change to the default stacked layout.{{/i}} +

    +
    +
    +
    + + + + +
    + +
    +
    +

    Inline

    +

    Wrap inline snippets of code with <code>.

    +
    +{{_i}}For example, <code>section</code> should be wrapped as inline.{{/i}}
    +
    +
    +
    +

    Basic block

    +

    {{_i}}Use <pre> for multiple lines of code. Be sure to escape any angle brackets in the code for proper rendering.{{/i}}

    +
    +<p>{{_i}}Sample text here...{{/i}}</p>
    +
    +
    +<pre>
    +  &lt;p&gt;{{_i}}Sample text here...{{/i}}&lt;/p&gt;
    +</pre>
    +
    +

    {{_i}}Note: Be sure to keep code within <pre> tags as close to the left as possible; it will render all tabs.{{/i}}

    +

    {{_i}}You may optionally add the .pre-scrollable class which will set a max-height of 350px and provide a y-axis scrollbar.{{/i}}

    +
    +
    +

    Google Prettify

    +

    Take the same <pre> element and add two optional classes for enhanced rendering.

    +
    +<p>{{_i}}Sample text here...{{/i}}</p>
    +
    +
    +<pre class="prettyprint
    +     linenums">
    +  &lt;p&gt;{{_i}}Sample text here...{{/i}}&lt;/p&gt;
    +</pre>
    +
    +

    {{_i}}Download google-code-prettify and view the readme for how to use.{{/i}}

    +
    +
    +
    + + + + +
    + + +

    {{_i}}Table markup{{/i}}

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Tag{{/i}}{{_i}}Description{{/i}}
    + <table> + + {{_i}}Wrapping element for displaying data in a tabular format{{/i}} +
    + <thead> + + {{_i}}Container element for table header rows (<tr>) to label table columns{{/i}} +
    + <tbody> + + {{_i}}Container element for table rows (<tr>) in the body of the table{{/i}} +
    + <tr> + + {{_i}}Container element for a set of table cells (<td> or <th>) that appears on a single row{{/i}} +
    + <td> + + {{_i}}Default table cell{{/i}} +
    + <th> + + {{_i}}Special table cell for column (or row, depending on scope and placement) labels{{/i}}
    + {{_i}}Must be used within a <thead>{{/i}} +
    + <caption> + + {{_i}}Description or summary of what the table holds, especially useful for screen readers{{/i}} +
    +
    +
    +
    +<table>
    +  <thead>
    +    <tr>
    +      <th>…</th>
    +      <th>…</th>
    +    </tr>
    +  </thead>
    +  <tbody>
    +    <tr>
    +      <td>…</td>
    +      <td>…</td>
    +    </tr>
    +  </tbody>
    +</table>
    +
    +
    +
    + +

    {{_i}}Table options{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}Class{{/i}}{{_i}}Description{{/i}}
    {{_i}}Default{{/i}}{{_i}}None{{/i}}{{_i}}No styles, just columns and rows{{/i}}
    {{_i}}Basic{{/i}} + .table + {{_i}}Only horizontal lines between rows{{/i}}
    {{_i}}Bordered{{/i}} + .table-bordered + {{_i}}Rounds corners and adds outer border{{/i}}
    {{_i}}Zebra-stripe{{/i}} + .table-striped + {{_i}}Adds light gray background color to odd rows (1, 3, 5, etc){{/i}}
    {{_i}}Condensed{{/i}} + .table-condensed + {{_i}}Cuts vertical padding in half, from 8px to 4px, within all td and th elements{{/i}}
    + + +

    {{_i}}Example tables{{/i}}

    + +

    1. {{_i}}Default table styles{{/i}}

    +
    +
    +

    {{_i}}Tables are automatically styled with only a few borders to ensure readability and maintain structure. With 2.0, the .table class is required.{{/i}}

    +
    +<table class="table">
    +  …
    +</table>
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #{{_i}}First Name{{/i}}{{_i}}Last Name{{/i}}{{_i}}Username{{/i}}
    1MarkOtto@mdo
    2JacobThornton@fat
    3Larrythe Bird@twitter
    +
    +
    + + +

    2. {{_i}}Striped table{{/i}}

    +
    +
    +

    {{_i}}Get a little fancy with your tables by adding zebra-striping—just add the .table-striped class.{{/i}}

    +

    {{_i}}Note: Striped tables use the :nth-child CSS selector and is not available in IE7-IE8.{{/i}}

    +
    +<table class="table table-striped">
    +  …
    +</table>
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #{{_i}}First Name{{/i}}{{_i}}Last Name{{/i}}{{_i}}Username{{/i}}
    1MarkOtto@mdo
    2JacobThornton@fat
    3Larrythe Bird@twitter
    +
    +
    + + +

    3. {{_i}}Bordered table{{/i}}

    +
    +
    +

    {{_i}}Add borders around the entire table and rounded corners for aesthetic purposes.{{/i}}

    +
    +<table class="table table-bordered">
    +  …
    +</table>
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #{{_i}}First Name{{/i}}{{_i}}Last Name{{/i}}{{_i}}Username{{/i}}
    1MarkOtto@mdo
    MarkOtto@TwBootstrap
    2JacobThornton@fat
    3Larry the Bird@twitter
    +
    +
    + + +

    4. {{_i}}Condensed table{{/i}}

    +
    +
    +

    {{_i}}Make your tables more compact by adding the .table-condensed class to cut table cell padding in half (from 8px to 4px).{{/i}}

    +
    +<table class="table table-condensed">
    +  …
    +</table>
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    #{{_i}}First Name{{/i}}{{_i}}Last Name{{/i}}{{_i}}Username{{/i}}
    1MarkOtto@mdo
    2JacobThornton@fat
    3Larry the Bird@twitter
    +
    +
    + + + +

    5. {{_i}}Combine them all!{{/i}}

    +
    +
    +

    {{_i}}Feel free to combine any of the table classes to achieve different looks by utilizing any of the available classes.{{/i}}

    +
    +<table class="table table-striped table-bordered table-condensed">
    +  ...
    +</table>
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Full name{{/i}}
    #{{_i}}First Name{{/i}}{{_i}}Last Name{{/i}}{{_i}}Username{{/i}}
    1MarkOtto@mdo
    2JacobThornton@fat
    3Larry the Bird@twitter
    +
    +
    +
    + + + + +
    + +
    +
    +

    {{_i}}Flexible HTML and CSS{{/i}}

    +

    {{_i}}The best part about forms in Bootstrap is that all your inputs and controls look great no matter how you build them in your markup. No superfluous HTML is required, but we provide the patterns for those who require it.{{/i}}

    +

    {{_i}}More complicated layouts come with succinct and scalable classes for easy styling and event binding, so you're covered at every step.{{/i}}

    +
    +
    +

    {{_i}}Four layouts included{{/i}}

    +

    {{_i}}Bootstrap comes with support for four types of form layouts:{{/i}}

    +
      +
    • {{_i}}Vertical (default){{/i}}
    • +
    • {{_i}}Search{{/i}}
    • +
    • {{_i}}Inline{{/i}}
    • +
    • {{_i}}Horizontal{{/i}}
    • +
    +

    {{_i}}Different types of form layouts require some changes to markup, but the controls themselves remain and behave the same.{{/i}}

    +
    +
    +

    {{_i}}Control states and more{{/i}}

    +

    {{_i}}Bootstrap's forms include styles for all the base form controls like input, textarea, and select you'd expect. But it also comes with a number of custom components like appended and prepended inputs and support for lists of checkboxes.{{/i}}

    +

    {{_i}}States like error, warning, and success are included for each type of form control. Also included are styles for disabled controls.{{/i}}

    +
    +
    + +

    {{_i}}Four types of forms{{/i}}

    +

    {{_i}}Bootstrap provides simple markup and styles for four styles of common web forms.{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}Class{{/i}}{{_i}}Description{{/i}}
    {{_i}}Vertical (default){{/i}}.form-vertical ({{_i}}not required{{/i}}){{_i}}Stacked, left-aligned labels over controls{{/i}}
    {{_i}}Inline{{/i}}.form-inline{{_i}}Left-aligned label and inline-block controls for compact style{{/i}}
    {{_i}}Search{{/i}}.form-search{{_i}}Extra-rounded text input for a typical search aesthetic{{/i}}
    {{_i}}Horizontal{{/i}}.form-horizontal{{_i}}Float left, right-aligned labels on same line as controls{{/i}}
    + + +

    {{_i}}Example forms using just form controls, no extra markup{{/i}}

    +
    +
    +

    {{_i}}Basic form{{/i}}

    +

    {{_i}}Smart and lightweight defaults without extra markup.{{/i}}

    +
    + + +

    {{_i}}Example block-level help text here.{{/i}}

    + + +
    +
    +<form class="well">
    +  <label>{{_i}}Label name{{/i}}</label>
    +  <input type="text" class="span3" placeholder="{{_i}}Type something…{{/i}}">
    +  <span class="help-block">Example block-level help text here.</span>
    +  <label class="checkbox">
    +    <input type="checkbox"> {{_i}}Check me out{{/i}}
    +  </label>
    +  <button type="submit" class="btn">{{_i}}Submit{{/i}}</button>
    +</form>
    +
    +
    +
    +

    {{_i}}Search form{{/i}}

    +

    {{_i}}Add .form-search to the form and .search-query to the input.{{/i}}

    + +
    +<form class="well form-search">
    +  <input type="text" class="input-medium search-query">
    +  <button type="submit" class="btn">{{_i}}Search{{/i}}</button>
    +</form>
    +
    + +

    {{_i}}Inline form{{/i}}

    +

    {{_i}}Add .form-inline to finesse the vertical alignment and spacing of form controls.{{/i}}

    +
    + + + + +
    +
    +<form class="well form-inline">
    +  <input type="text" class="input-small" placeholder="{{_i}}Email{{/i}}">
    +  <input type="password" class="input-small" placeholder="{{_i}}Password{{/i}}">
    +  <label class="checkbox">
    +    <input type="checkbox"> {{_i}}Remember me{{/i}}
    +  </label>
    +  <button type="submit" class="btn">{{_i}}Sign in{{/i}}</button>
    +</form>
    +
    +
    +
    + +
    + +

    {{_i}}Horizontal forms{{/i}}

    +
    +
    +

    {{_i}}{{/i}}

    +

    {{_i}}Shown on the right are all the default form controls we support. Here's the bulleted list:{{/i}}

    +
      +
    • {{_i}}text inputs (text, password, email, etc){{/i}}
    • +
    • {{_i}}checkbox{{/i}}
    • +
    • {{_i}}radio{{/i}}
    • +
    • {{_i}}select{{/i}}
    • +
    • {{_i}}multiple select{{/i}}
    • +
    • {{_i}}file input{{/i}}
    • +
    • {{_i}}textarea{{/i}}
    • +
    +
    +
    +
    +
    +
    + +
    + +

    {{_i}}In addition to freeform text, any HTML5 text-based input appears like so.{{/i}}

    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + + +
    +
    +
    +

    {{_i}}Example markup{{/i}}

    +

    {{_i}}Given the above example form layout, here's the markup associated with the first input and control group. The .control-group, .control-label, and .controls classes are all required for styling.{{/i}}

    +
    +<form class="form-horizontal">
    +  <fieldset>
    +    <legend>{{_i}}Legend text{{/i}}</legend>
    +    <div class="control-group">
    +      <label class="control-label" for="input01">{{_i}}Text input{{/i}}</label>
    +      <div class="controls">
    +        <input type="text" class="input-xlarge" id="input01">
    +        <p class="help-block">{{_i}}Supporting help text{{/i}}</p>
    +      </div>
    +    </div>
    +  </fieldset>
    +</form>
    +
    +
    +
    + +
    + +

    {{_i}}Form control states{{/i}}

    +
    +
    +

    {{_i}}Bootstrap features styles for browser-supported focused and disabled states. We remove the default Webkit outline and apply a box-shadow in its place for :focus.{{/i}}

    +
    +

    {{_i}}Form validation{{/i}}

    +

    {{_i}}It also includes validation styles for errors, warnings, and success. To use, add the error class to the surrounding .control-group.{{/i}}

    +
    +<fieldset
    +  class="control-group error">
    +  …
    +</fieldset>
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + Some value here +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + + {{_i}}Something may have gone wrong{{/i}} +
    +
    +
    + +
    + + {{_i}}Please correct the error{{/i}} +
    +
    +
    + +
    + + {{_i}}Woohoo!{{/i}} +
    +
    +
    + +
    + + {{_i}}Woohoo!{{/i}} +
    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +

    {{_i}}Extending form controls{{/i}}

    +
    +
    +

    {{_i}}Prepend & append inputs{{/i}}

    +

    {{_i}}Input groups—with appended or prepended text—provide an easy way to give more context for your inputs. Great examples include the @ sign for Twitter usernames or $ for finances.{{/i}}

    +
    +

    {{_i}}Checkboxes and radios{{/i}}

    +

    {{_i}}Up to v1.4, Bootstrap required extra markup around checkboxes and radios to stack them. Now, it's a simple matter of repeating the <label class="checkbox"> that wraps the <input type="checkbox">.{{/i}}

    +

    {{_i}}Inline checkboxes and radios are also supported. Just add .inline to any .checkbox or .radio and you're done.{{/i}}

    +
    +

    {{_i}}Inline forms and append/prepend{{/i}}

    +

    {{_i}}To use prepend or append inputs in an inline form, be sure to place the .add-on and input on the same line, without spaces.{{/i}}

    +
    +

    {{_i}}Form help text{{/i}}

    +

    {{_i}}To add help text for your form inputs, include inline help text with <span class="help-inline"> or a help text block with <p class="help-block"> after the input element.{{/i}}

    +
    +
    +
    +
    +
    + +
    + + + + + + +

    {{_i}}Use the same .span* classes from the grid system for input sizes.{{/i}}

    +
    +
    +
    + +
    + + + +

    {{_i}}You may also use static classes that don't map to the grid, adapt to the responsive CSS styles, or account for varying types of controls (e.g., input vs. select).{{/i}}

    +
    +
    +
    + +
    +
    + @ +
    +

    {{_i}}Here's some help text{{/i}}

    +
    +
    +
    + +
    +
    + .00 +
    + {{_i}}Here's more help text{{/i}} +
    +
    +
    + +
    +
    + $.00 +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    + + + +
    +
    +
    + +
    + + + +

    {{_i}}Note: Labels surround all the options for much larger click areas and a more usable form.{{/i}}

    +
    +
    +
    + +
    + + +
    +
    +
    + + +
    +
    +
    +
    +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Button{{/i}}{{_i}}class=""{{/i}}{{_i}}Description{{/i}}
    btn{{_i}}Standard gray button with gradient{{/i}}
    btn btn-primary{{_i}}Provides extra visual weight and identifies the primary action in a set of buttons{{/i}}
    btn btn-info{{_i}}Used as an alternative to the default styles{{/i}}
    btn btn-success{{_i}}Indicates a successful or positive action{{/i}}
    btn btn-warning{{_i}}Indicates caution should be taken with this action{{/i}}
    btn btn-danger{{_i}}Indicates a dangerous or potentially negative action{{/i}}
    btn btn-inverse{{_i}}Alternate dark gray button, not tied to a semantic action or use{{/i}}
    + +
    +
    +

    {{_i}}Buttons for actions{{/i}}

    +

    {{_i}}As a convention, buttons should only be used for actions while hyperlinks are to be used for objects. For instance, "Download" should be a button while "recent activity" should be a link.{{/i}}

    +

    {{_i}}Button styles can be applied to anything with the .btn class applied. However, typically you'll want to apply these to only <a> and <button> elements.{{/i}}

    +

    {{_i}}Cross browser compatibility{{/i}}

    +

    {{_i}}IE9 doesn't crop background gradients on rounded corners, so we remove it. Related, IE9 jankifies disabled button elements, rendering text gray with a nasty text-shadow that we cannot fix.{{/i}}

    +
    +
    +

    {{_i}}Multiple sizes{{/i}}

    +

    {{_i}}Fancy larger or smaller buttons? Add .btn-large, .btn-small, or .btn-mini for two additional sizes.{{/i}}

    +

    + + +

    +

    + + +

    +

    + + +

    +
    +

    {{_i}}Disabled state{{/i}}

    +

    {{_i}}For disabled buttons, add the .disabled class to links and the disabled attribute for <button> elements.{{/i}}

    +

    + {{_i}}Primary link{{/i}} + {{_i}}Link{{/i}} +

    +

    + + +

    +

    + {{_i}}Heads up!{{/i}} + {{_i}}We use .disabled as a utility class here, similar to the common .active class, so no prefix is required.{{/i}} +

    +
    +
    +

    {{_i}}One class, multiple tags{{/i}}

    +

    {{_i}}Use the .btn class on an <a>, <button>, or <input> element.{{/i}}

    +
    +{{_i}}Link{{/i}} + + + +
    +
    +<a class="btn" href="">{{_i}}Link{{/i}}</a>
    +<button class="btn" type="submit">
    +  {{_i}}Button{{/i}}
    +</button>
    +<input class="btn" type="button"
    +         value="{{_i}}Input{{/i}}">
    +<input class="btn" type="submit"
    +         value="{{_i}}Submit{{/i}}">
    +
    +

    {{_i}}As a best practice, try to match the element for you context to ensure matching cross-browser rendering. If you have an input, use an <input type="submit"> for your button.{{/i}}

    +
    +
    +
    + + + + +
    + +
    +
    +
      +
    • icon-glass
    • +
    • icon-music
    • +
    • icon-search
    • +
    • icon-envelope
    • +
    • icon-heart
    • +
    • icon-star
    • +
    • icon-star-empty
    • +
    • icon-user
    • +
    • icon-film
    • +
    • icon-th-large
    • +
    • icon-th
    • +
    • icon-th-list
    • +
    • icon-ok
    • +
    • icon-remove
    • +
    • icon-zoom-in
    • +
    • icon-zoom-out
    • +
    • icon-off
    • +
    • icon-signal
    • +
    • icon-cog
    • +
    • icon-trash
    • +
    • icon-home
    • +
    • icon-file
    • +
    • icon-time
    • +
    • icon-road
    • +
    • icon-download-alt
    • +
    • icon-download
    • +
    • icon-upload
    • +
    • icon-inbox
    • +
    • icon-play-circle
    • +
    • icon-repeat
    • +
    • icon-refresh
    • +
    • icon-list-alt
    • +
    • icon-lock
    • +
    • icon-flag
    • +
    • icon-headphones
    • +
    +
    +
    +
      +
    • icon-volume-off
    • +
    • icon-volume-down
    • +
    • icon-volume-up
    • +
    • icon-qrcode
    • +
    • icon-barcode
    • +
    • icon-tag
    • +
    • icon-tags
    • +
    • icon-book
    • +
    • icon-bookmark
    • +
    • icon-print
    • +
    • icon-camera
    • +
    • icon-font
    • +
    • icon-bold
    • +
    • icon-italic
    • +
    • icon-text-height
    • +
    • icon-text-width
    • +
    • icon-align-left
    • +
    • icon-align-center
    • +
    • icon-align-right
    • +
    • icon-align-justify
    • +
    • icon-list
    • +
    • icon-indent-left
    • +
    • icon-indent-right
    • +
    • icon-facetime-video
    • +
    • icon-picture
    • +
    • icon-pencil
    • +
    • icon-map-marker
    • +
    • icon-adjust
    • +
    • icon-tint
    • +
    • icon-edit
    • +
    • icon-share
    • +
    • icon-check
    • +
    • icon-move
    • +
    • icon-step-backward
    • +
    • icon-fast-backward
    • +
    +
    +
    +
      +
    • icon-backward
    • +
    • icon-play
    • +
    • icon-pause
    • +
    • icon-stop
    • +
    • icon-forward
    • +
    • icon-fast-forward
    • +
    • icon-step-forward
    • +
    • icon-eject
    • +
    • icon-chevron-left
    • +
    • icon-chevron-right
    • +
    • icon-plus-sign
    • +
    • icon-minus-sign
    • +
    • icon-remove-sign
    • +
    • icon-ok-sign
    • +
    • icon-question-sign
    • +
    • icon-info-sign
    • +
    • icon-screenshot
    • +
    • icon-remove-circle
    • +
    • icon-ok-circle
    • +
    • icon-ban-circle
    • +
    • icon-arrow-left
    • +
    • icon-arrow-right
    • +
    • icon-arrow-up
    • +
    • icon-arrow-down
    • +
    • icon-share-alt
    • +
    • icon-resize-full
    • +
    • icon-resize-small
    • +
    • icon-plus
    • +
    • icon-minus
    • +
    • icon-asterisk
    • +
    • icon-exclamation-sign
    • +
    • icon-gift
    • +
    • icon-leaf
    • +
    • icon-fire
    • +
    • icon-eye-open
    • +
    +
    +
    +
      +
    • icon-eye-close
    • +
    • icon-warning-sign
    • +
    • icon-plane
    • +
    • icon-calendar
    • +
    • icon-random
    • +
    • icon-comment
    • +
    • icon-magnet
    • +
    • icon-chevron-up
    • +
    • icon-chevron-down
    • +
    • icon-retweet
    • +
    • icon-shopping-cart
    • +
    • icon-folder-close
    • +
    • icon-folder-open
    • +
    • icon-resize-vertical
    • +
    • icon-resize-horizontal
    • +
    • icon-hdd
    • +
    • icon-bullhorn
    • +
    • icon-bell
    • +
    • icon-certificate
    • +
    • icon-thumbs-up
    • +
    • icon-thumbs-down
    • +
    • icon-hand-right
    • +
    • icon-hand-left
    • +
    • icon-hand-up
    • +
    • icon-hand-down
    • +
    • icon-circle-arrow-right
    • +
    • icon-circle-arrow-left
    • +
    • icon-circle-arrow-up
    • +
    • icon-circle-arrow-down
    • +
    • icon-globe
    • +
    • icon-wrench
    • +
    • icon-tasks
    • +
    • icon-filter
    • +
    • icon-briefcase
    • +
    • icon-fullscreen
    • +
    +
    +
    + +
    + +
    +
    +

    {{_i}}Built as a sprite{{/i}}

    +

    {{_i}}Instead of making every icon an extra request, we've compiled them into a sprite—a bunch of images in one file that uses CSS to position the images with background-position. This is the same method we use on Twitter.com and it has worked well for us.{{/i}}

    +

    {{_i}}All icons classes are prefixed with .icon- for proper namespacing and scoping, much like our other components. This will help avoid conflicts with other tools.{{/i}}

    +

    {{_i}}Glyphicons has granted us use of the Halflings set in our open-source toolkit so long as we provide a link and credit here in the docs. Please consider doing the same in your projects.{{/i}}

    +
    +
    +

    {{_i}}How to use{{/i}}

    +

    {{_i}}Bootstrap uses an <i> tag for all icons, but they have no case class—only a shared prefix. To use, place the following code just about anywhere:{{/i}}

    +
    +<i class="icon-search"></i>
    +
    +

    {{_i}}There are also styles available for inverted (white) icons, made ready with one extra class:{{/i}}

    +
    +<i class="icon-search icon-white"></i>
    +
    +

    {{_i}}There are 120 classes to choose from for your icons. Just add an <i> tag with the right classes and you're set. You can find the full list in sprites.less or right here in this document.{{/i}}

    +

    + {{_i}}Heads up!{{/i}} + {{_i}}When using beside strings of text, as in buttons or nav links, be sure to leave a space after the <i> tag for proper spacing.{{/i}} +

    +
    +
    +

    {{_i}}Use cases{{/i}}

    +

    {{_i}}Icons are great, but where would one use them? Here are a few ideas:{{/i}}

    +
      +
    • {{_i}}As visuals for your sidebar navigation{{/i}}
    • +
    • {{_i}}For a purely icon-driven navigation{{/i}}
    • +
    • {{_i}}For buttons to help convey the meaning of an action{{/i}}
    • +
    • {{_i}}With links to share context on a user's destination{{/i}}
    • +
    +

    {{_i}}Essentially, anywhere you can put an <i> tag, you can put an icon.{{/i}}

    +
    +
    + +

    {{_i}}Examples{{/i}}

    +

    {{_i}}Use them in buttons, button groups for a toolbar, navigation, or prepended form inputs.{{/i}}

    + +
    diff --git a/test/public/bootstrap/docs/templates/pages/components.mustache b/test/public/bootstrap/docs/templates/pages/components.mustache new file mode 100644 index 0000000..8e81a95 --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/components.mustache @@ -0,0 +1,1815 @@ + +
    +

    {{_i}}Components{{/i}}

    +

    {{_i}}Dozens of reusable components are built into Bootstrap to provide navigation, alerts, popovers, and much more.{{/i}}

    + +
    + + + + +
    + +
    +
    +

    {{_i}}Button groups{{/i}}

    +

    {{_i}}Use button groups to join multiple buttons together as one composite component. Build them with a series of <a> or <button> elements.{{/i}}

    +

    {{_i}}Best practices{{/i}}

    +

    {{_i}}We recommend the following guidelines for using button groups and toolbars:{{/i}}

    +
      +
    • {{_i}}Always use the same element in a single button group, <a> or <button>.{{/i}}
    • +
    • {{_i}}Don't mix buttons of different colors in the same button group.{{/i}}
    • +
    • {{_i}}Use icons in addition to or instead of text, but be sure include alt and title text where appropriate.{{/i}}
    • +
    +

    {{_i}}Related Button groups with dropdowns (see below) should be called out separately and always include a dropdown caret to indicate intended behavior.{{/i}}

    +
    +
    +

    {{_i}}Default example{{/i}}

    +

    {{_i}}Here's how the HTML looks for a standard button group built with anchor tag buttons:{{/i}}

    +
    +
    + + + +
    +
    +
    +<div class="btn-group">
    +  <button class="btn">1</button>
    +  <button class="btn">2</button>
    +  <button class="btn">3</button>
    +</div>
    +
    +

    {{_i}}Toolbar example{{/i}}

    +

    {{_i}}Combine sets of <div class="btn-group"> into a <div class="btn-toolbar"> for more complex components.{{/i}}

    +
    +
    + + + + +
    +
    + + + +
    +
    + +
    +
    +
    +<div class="btn-toolbar">
    +  <div class="btn-group">
    +    ...
    +  </div>
    +</div>
    +
    +
    +
    +

    {{_i}}Checkbox and radio flavors{{/i}}

    +

    {{_i}}Button groups can also function as radios, where only one button may be active, or checkboxes, where any number of buttons may be active. View the Javascript docs for that.{{/i}}

    +

    {{_i}}Get the javascript »{{/i}}

    +

    {{_i}}Dropdowns in button groups{{/i}}

    +

    {{_i}}Heads up!{{/i}} {{_i}}Buttons with dropdowns must be individually wrapped in their own .btn-group within a .btn-toolbar for proper rendering.{{/i}}

    +
    +
    +
    + + + + +
    + + +

    {{_i}}Button dropdowns{{/i}}

    +
    +
    +

    {{_i}}Overview and examples{{/i}}

    +

    {{_i}}Use any button to trigger a dropdown menu by placing it within a .btn-group and providing the proper menu markup.{{/i}}

    + + +
    +
    +

    {{_i}}Example markup{{/i}}

    +

    {{_i}}Similar to a button group, our markup uses regular button markup, but with a handful of additions to refine the style and support Bootstrap's dropdown jQuery plugin.{{/i}}

    +
    +<div class="btn-group">
    +  <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
    +    {{_i}}Action{{/i}}
    +    <span class="caret"></span>
    +  </a>
    +  <ul class="dropdown-menu">
    +    <!-- {{_i}}dropdown menu links{{/i}} -->
    +  </ul>
    +</div>
    +
    +
    +
    +
    +
    +

    {{_i}}Works with all button sizes{{/i}}

    +

    {{_i}}Button dropdowns work at any size. your button sizes to .btn-large, .btn-small, or .btn-mini.{{/i}}

    + +
    +
    +

    {{_i}}Requires javascript{{/i}}

    +

    {{_i}}Button dropdowns require the Bootstrap dropdown plugin to function.{{/i}}

    +

    {{_i}}In some cases—like mobile—dropdown menus will extend outside the viewport. You need to resolve the alignment manually or with custom javascript.{{/i}}

    +
    +
    +
    + +

    {{_i}}Split button dropdowns{{/i}}

    +
    +
    +

    {{_i}}Overview and examples{{/i}}

    +

    {{_i}}Building on the button group styles and markup, we can easily create a split button. Split buttons feature a standard action on the left and a dropdown toggle on the right with contextual links.{{/i}}

    + + + +

    {{_i}}Sizes{{/i}}

    +

    {{_i}}Utilize the extra button classes .btn-mini, .btn-small, or .btn-large for sizing.{{/i}}

    + + + +
    +<div class="btn-group">
    +  ...
    +  <ul class="dropdown-menu pull-right">
    +    <!-- {{_i}}dropdown menu links{{/i}} -->
    +  </ul>
    +</div>
    +
    +
    +
    +

    {{_i}}Example markup{{/i}}

    +

    {{_i}}We expand on the normal button dropdowns to provide a second button action that operates as a separate dropdown trigger.{{/i}}

    +
    +<div class="btn-group">
    +  <button class="btn">{{_i}}Action{{/i}}</button>
    +  <button class="btn dropdown-toggle" data-toggle="dropdown">
    +    <span class="caret"></span>
    +  </button>
    +  <ul class="dropdown-menu">
    +    <!-- {{_i}}dropdown menu links{{/i}} -->
    +  </ul>
    +</div>
    +
    +

    {{_i}}Dropup menus{{/i}}

    +

    {{_i}}Dropdown menus can also be toggled from the bottom up by adding a single class to the immediate parent of .dropdown-menu. It will flip the direction of the .caret and reposition the menu itself to move from the bottom up instead of top down.{{/i}}

    + +
    +<div class="btn-group dropup">
    +  <button class="btn">{{_i}}Dropup{{/i}}</button>
    +  <button class="btn dropdown-toggle" data-toggle="dropdown">
    +    <span class="caret"></span>
    +  </button>
    +  <ul class="dropdown-menu">
    +    <!-- {{_i}}dropdown menu links{{/i}} -->
    +  </ul>
    +</div>
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + +
    + + +

    {{_i}}Multicon-page pagination{{/i}}

    +
    +
    +

    {{_i}}When to use{{/i}}

    +

    {{_i}}Ultra simplistic and minimally styled pagination inspired by Rdio, great for apps and search results. The large block is hard to miss, easily scalable, and provides large click areas.{{/i}}

    +

    {{_i}}Stateful page links{{/i}}

    +

    {{_i}}Links are customizable and work in a number of circumstances with the right class. .disabled for unclickable links and .active for current page.{{/i}}

    +

    {{_i}}Flexible alignment{{/i}}

    +

    {{_i}}Add either of two optional classes to change the alignment of pagination links: .pagination-centered and .pagination-right.{{/i}}

    +
    +
    +

    {{_i}}Examples{{/i}}

    +

    {{_i}}The default pagination component is flexible and works in a number of variations.{{/i}}

    + + + + +
    +
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}Wrapped in a <div>, pagination is just a <ul>.{{/i}}

    +
    +<div class="pagination">
    +  <ul>
    +    <li><a href="#">Prev</a></li>
    +    <li class="active">
    +      <a href="#">1</a>
    +    </li>
    +    <li><a href="#">2</a></li>
    +    <li><a href="#">3</a></li>
    +    <li><a href="#">4</a></li>
    +    <li><a href="#">Next</a></li>
    +  </ul>
    +</div>
    +
    +
    +
    + +

    {{_i}}Pager{{/i}} {{_i}}For quick previous and next links{{/i}}

    +
    +
    +

    {{_i}}About pager{{/i}}

    +

    {{_i}}The pager component is a set of links for simple pagination implementations with light markup and even lighter styles. It's great for simple sites like blogs or magazines.{{/i}}

    +

    {{_i}}Optional disabled state{{/i}}

    +

    {{_i}}Pager links also use the general .disabled class from the pagination.{{/i}}

    +
    +
    +

    {{_i}}Default example{{/i}}

    +

    {{_i}}By default, the pager centers links.{{/i}}

    + +
    +<ul class="pager">
    +  <li>
    +    <a href="#">{{_i}}Previous{{/i}}</a>
    +  </li>
    +  <li>
    +    <a href="#">{{_i}}Next{{/i}}</a>
    +  </li>
    +</ul>
    +
    +
    +
    +

    {{_i}}Aligned links{{/i}}

    +

    {{_i}}Alternatively, you can align each link to the sides:{{/i}}

    + +
    +<ul class="pager">
    +  <li class="previous">
    +    <a href="#">{{_i}}&larr; Older{{/i}}</a>
    +  </li>
    +  <li class="next">
    +    <a href="#">{{_i}}Newer &rarr;{{/i}}</a>
    +  </li>
    +</ul>
    +
    +
    +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Labels{{/i}}{{_i}}Markup{{/i}}
    + {{_i}}Default{{/i}} + + <span class="label">{{_i}}Default{{/i}}</span> +
    + {{_i}}Success{{/i}} + + <span class="label label-success">{{/_i}}Success{{/i}}</span> +
    + {{_i}}Warning{{/i}} + + <span class="label label-warning">{{_i}}Warning{{/i}}</span> +
    + {{_i}}Important{{/i}} + + <span class="label label-important">{{_i}}Important{{/i}}</span> +
    + {{_i}}Info{{/i}} + + <span class="label label-info">{{_i}}Info{{/i}}</span> +
    + {{_i}}Inverse{{/i}} + + <span class="label label-inverse">{{_i}}Inverse{{/i}}</span> +
    +
    + + + + +
    + +
    +
    +

    About

    +

    {{_i}}Badges are small, simple components for displaying an indicator or count of some sort. They're commonly found in email clients like Mail.app or on mobile apps for push notifications.{{/i}}

    +
    +
    +

    Available classes

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}Example{{/i}}{{_i}}Markup{{/i}}
    + {{_i}}Default{{/i}} + + 1 + + <span class="badge">1</span> +
    + {{_i}}Success{{/i}} + + 2 + + <span class="badge badge-success">2</span> +
    + {{_i}}Warning{{/i}} + + 4 + + <span class="badge badge-warning">4</span> +
    + {{_i}}Important{{/i}} + + 6 + + <span class="badge badge-important">6</span> +
    + {{_i}}Info{{/i}} + + 8 + + <span class="badge badge-info">8</span> +
    + {{_i}}Inverse{{/i}} + + 10 + + <span class="badge badge-inverse">10</span> +
    +
    +
    +
    + + + + +
    + +

    {{_i}}Hero unit{{/i}}

    +
    +
    +

    {{_i}}Bootstrap provides a lightweight, flexible component called a hero unit to showcase content on your site. It works well on marketing and content-heavy sites.{{/i}}

    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}Wrap your content in a div like so:{{/i}}

    +
    +<div class="hero-unit">
    +  <h1>{{_i}}Heading{{/i}}</h1>
    +  <p>{{_i}}Tagline{{/i}}</p>
    +  <p>
    +    <a class="btn btn-primary btn-large">
    +      {{_i}}Learn more{{/i}}
    +    </a>
    +  </p>
    +</div>
    +
    +
    +
    +
    +

    {{_i}}Hello, world!{{/i}}

    +

    {{_i}}This is a simple hero unit, a simple jumbotron-style component for calling extra attention to featured content or information.{{/i}}

    +

    {{_i}}Learn more{{/i}}

    +
    +
    +
    +

    {{_i}}Page header{{/i}}

    +
    +
    +

    {{_i}}A simple shell for an h1 to appropriately space out and segment sections of content on a page. It can utilize the h1's default small, element as well most other components (with additional styles).{{/i}}

    +
    +
    + +
    +<div class="page-header">
    +  <h1>{{_i}}Example page header{{/i}}</h1>
    +</div>
    +
    +
    +
    +
    + + + + +
    + + +
    +
    +

    {{_i}}Default thumbnails{{/i}}

    +

    {{_i}}By default, Bootstrap's thumbnails are designed to showcase linked images with minimal required markup.{{/i}}

    + +
    +
    +

    {{_i}}Highly customizable{{/i}}

    +

    {{_i}}With a bit of extra markup, it's possible to add any kind of HTML content like headings, paragraphs, or buttons into thumbnails.{{/i}}

    +
      +
    • +
      + +
      +
      {{_i}}Thumbnail label{{/i}}
      +

      Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

      +

      {{_i}}Action{{/i}} {{_i}}Action{{/i}}

      +
      +
      +
    • +
    • +
      + +
      +
      {{_i}}Thumbnail label{{/i}}
      +

      Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.

      +

      {{_i}}Action{{/i}} {{_i}}Action{{/i}}

      +
      +
      +
    • +
    +
    +
    + +
    +
    +

    {{_i}}Why use thumbnails{{/i}}

    +

    {{_i}}Thumbnails (previously .media-grid up until v1.4) are great for grids of photos or videos, image search results, retail products, portfolios, and much more. They can be links or static content.{{/i}}

    +
    +
    +

    {{_i}}Simple, flexible markup{{/i}}

    +

    {{_i}}Thumbnail markup is simple—a ul with any number of li elements is all that is required. It's also super flexible, allowing for any type of content with just a bit more markup to wrap your contents.{{/i}}

    +
    +
    +

    {{_i}}Uses grid column sizes{{/i}}

    +

    {{_i}}Lastly, the thumbnails component uses existing grid system classes—like .span2 or .span3—for control of thumbnail dimensions.{{/i}}

    +
    +
    + +
    +
    +

    {{_i}}The markup{{/i}}

    +

    {{_i}}As mentioned previously, the required markup for thumbnails is light and straightforward. Here's a look at the default setup for linked images:{{/i}}

    +
    +<ul class="thumbnails">
    +  <li class="span3">
    +    <a href="#" class="thumbnail">
    +      <img src="http://placehold.it/260x180" alt="">
    +    </a>
    +  </li>
    +  ...
    +</ul>
    +
    +

    {{_i}}For custom HTML content in thumbnails, the markup changes slightly. To allow block level content anywhere, we swap the <a> for a <div> like so:{{/i}}

    +
    +<ul class="thumbnails">
    +  <li class="span3">
    +    <div class="thumbnail">
    +      <img src="http://placehold.it/260x180" alt="">
    +      <h5>{{_i}}Thumbnail label{{/i}}</h5>
    +      <p>{{_i}}Thumbnail caption right here...{{/i}}</p>
    +    </div>
    +  </li>
    +  ...
    +</ul>
    +
    +
    +
    +

    {{_i}}More examples{{/i}}

    +

    {{_i}}Explore all your options with the various grid classes available to you. You can also mix and match different sizes.{{/i}}

    + +
    +
    + +
    + + + + +
    + + +

    {{_i}}Lightweight defaults{{/i}}

    +
    +
    +

    {{_i}}Rewritten base class{{/i}}

    +

    {{_i}}With Bootstrap 2, we've simplified the base class: .alert instead of .alert-message. We've also reduced the minimum required markup—no <p> is required by default, just the outer <div>.{{/i}}

    +

    {{_i}}Single alert message{{/i}}

    +

    {{_i}}For a more durable component with less code, we've removed the differentiating look for block alerts, messages that come with more padding and typically more text. The class also has changed to .alert-block.{{/i}}

    +
    +

    {{_i}}Goes great with javascript{{/i}}

    +

    {{_i}}Bootstrap comes with a great jQuery plugin that supports alert messages, making dismissing them quick and easy.{{/i}}

    +

    {{_i}}Get the plugin »{{/i}}

    +
    +
    +

    {{_i}}Example alerts{{/i}}

    +

    {{_i}}Wrap your message and an optional close icon in a div with simple class.{{/i}}

    +
    + + {{_i}}Warning!{{/i}} {{_i}}Best check yo self, you're not looking too good.{{/i}} +
    +
    +<div class="alert">
    +  <button class="close" data-dismiss="alert">×</button>
    +  <strong>{{_i}}Warning!{{/i}}</strong> {{_i}}Best check yo self, you're not looking too good.{{/i}}
    +</div>
    +
    +

    {{_i}}Heads up!{{/i}} {{_i}}iOS devices require an href="#" for the dismissal of alerts. Be sure to include it and the data attribute for anchor close icons. Alternatively, you may use a button element with the data attribute, which we have opted to do for our docs.{{/i}}

    +

    {{_i}}Easily extend the standard alert message with two optional classes: .alert-block for more padding and text controls and .alert-heading for a matching heading.{{/i}}

    +
    + +

    {{_i}}Warning!{{/i}}

    +

    {{_i}}Best check yo self, you're not looking too good.{{/i}} Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

    +
    +
    +<div class="alert alert-block">
    +  <a class="close" data-dismiss="alert" href="#">×</a>
    +  <h4 class="alert-heading">{{_i}}Warning!{{/i}}</h4>
    +  {{_i}}Best check yo self, you're not...{{/i}}
    +</div>
    +
    +
    +
    + +

    {{_i}}Contextual alternatives{{/i}} {{_i}}Add optional classes to change an alert's connotation{{/i}}

    +
    +
    +

    {{_i}}Error or danger{{/i}}

    +
    + + {{_i}}Oh snap!{{/i}} {{_i}}Change a few things up and try submitting again.{{/i}} +
    +
    +<div class="alert alert-error">
    +  ...
    +</div>
    +
    +
    +
    +

    {{_i}}Success{{/i}}

    +
    + + {{_i}}Well done!{{/i}} {{_i}}You successfully read this important alert message.{{/i}} +
    +
    +<div class="alert alert-success">
    +  ...
    +</div>
    +
    +
    +
    +

    {{_i}}Information{{/i}}

    +
    + + {{_i}}Heads up!{{/i}} {{_i}}This alert needs your attention, but it's not super important.{{/i}} +
    +
    +<div class="alert alert-info">
    +  ...
    +</div>
    +
    +
    +
    + +
    + + + + +
    + + +

    {{_i}}Examples and markup{{/i}}

    +
    +
    +

    {{_i}}Basic{{/i}}

    +

    {{_i}}Default progress bar with a vertical gradient.{{/i}}

    +
    +
    +
    +
    +<div class="progress">
    +  <div class="bar"
    +       style="width: 60%;"></div>
    +</div>
    +
    +
    +
    +

    {{_i}}Striped{{/i}}

    +

    {{_i}}Uses a gradient to create a striped effect (no IE).{{/i}}

    +
    +
    +
    +
    +<div class="progress progress-striped">
    +  <div class="bar"
    +       style="width: 20%;"></div>
    +</div>
    +
    +
    +
    +

    {{_i}}Animated{{/i}}

    +

    {{_i}}Takes the striped example and animates it (no IE).{{/i}}

    +
    +
    +
    +
    +<div class="progress progress-striped
    +     active">
    +  <div class="bar"
    +       style="width: 40%;"></div>
    +</div>
    +
    +
    +
    + +

    {{_i}}Options and browser support{{/i}}

    +
    +
    +

    {{_i}}Additional colors{{/i}}

    +

    {{_i}}Progress bars use some of the same button and alert classes for consistent styles.{{/i}}

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    {{_i}}Striped bars{{/i}}

    +

    {{_i}}Similar to the solid colors, we have varied striped progress bars.{{/i}}

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    {{_i}}Behavior{{/i}}

    +

    {{_i}}Progress bars use CSS3 transitions, so if you dynamically adjust the width via javascript, it will smoothly resize.{{/i}}

    +

    {{_i}}If you use the .active class, your .progress-striped progress bars will animate the stripes left to right.{{/i}}

    +
    +
    +

    {{_i}}Browser support{{/i}}

    +

    {{_i}}Progress bars use CSS3 gradients, transitions, and animations to achieve all their effects. These features are not supported in IE7-9 or older versions of Firefox.{{/i}}

    +

    {{_i}}Opera and IE do not support animations at this time.{{/i}}

    +
    +
    + +
    + + + + + + +
    + +
    +
    +

    {{_i}}Wells{{/i}}

    +

    {{_i}}Use the well as a simple effect on an element to give it an inset effect.{{/i}}

    +
    + {{_i}}Look, I'm in a well!{{/i}} +
    +
    +<div class="well">
    +  ...
    +</div>
    +
    +
    +
    +

    {{_i}}Close icon{{/i}}

    +

    {{_i}}Use the generic close icon for dismissing content like modals and alerts.{{/i}}

    +

    +
    <button class="close">&times;</button>
    +

    {{_i}}iOS devices require an href="#" for click events if you rather use an anchor.{{/i}}

    +
    <a class="close" href="#">&times;</a>
    +
    +
    +
    diff --git a/test/public/bootstrap/docs/templates/pages/download.mustache b/test/public/bootstrap/docs/templates/pages/download.mustache new file mode 100644 index 0000000..ffade09 --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/download.mustache @@ -0,0 +1,338 @@ + +
    +

    {{_i}}Customize and download{{/i}}

    +

    {{_i}}Download the full repository or customize your entire Bootstrap build by selecting only the components, javascript plugins, and assets you need.{{/i}}

    + +
    + +
    + +
    +
    +

    {{_i}}Scaffolding{{/i}}

    + + + + +

    {{_i}}Base CSS{{/i}}

    + + + + + + + +
    +
    +

    {{_i}}Components{{/i}}

    + + + + + + + + + + +
    +
    +

    {{_i}}JS Components{{/i}}

    + + + + + + +
    +
    +

    {{_i}}Miscellaneous{{/i}}

    + + + + +

    {{_i}}Responsive{{/i}}

    + + + + + +
    +
    +
    + +
    + +
    +
    + + + + + + +
    +
    + + + + + + +
    +
    +

    {{_i}}Heads up!{{/i}}

    +

    {{_i}}All checked plugins will be compiled into a single file, bootstrap.js. All plugins require the latest version of jQuery to be included.{{/i}}

    +
    +
    +
    + + +
    + +
    +
    +

    {{_i}}Scaffolding{{/i}}

    + + + + + +

    {{_i}}Links{{/i}}

    + + + + +

    {{_i}}Colors{{/i}}

    + + + + + + + + + + + + + + + +

    {{_i}}Sprites{{/i}}

    + + + + + +
    +
    +

    {{_i}}Grid system{{/i}}

    + + + + + + +

    {{_i}}Fluid grid system{{/i}}

    + + + + + +

    {{_i}}Typography{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    {{_i}}Tables{{/i}}

    + + + + + + + + + +

    {{_i}}Navbar{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    {{_i}}Dropdowns{{/i}}

    + + + + + + + + + + +
    +
    +

    {{_i}}Forms{{/i}}

    + + + + + + + + + + + + + + + + + + +

    {{_i}}Form states & alerts{{/i}}

    + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + {{_i}}Customize and Download{{/i}} +

    {{_i}}What's included?{{/i}}

    +

    {{_i}}Downloads include compiled CSS, compiled and minified CSS, and compiled jQuery plugins, all nicely packed up into a zipball for your convenience.{{/i}}

    +
    +
    diff --git a/test/public/bootstrap/docs/templates/pages/examples.mustache b/test/public/bootstrap/docs/templates/pages/examples.mustache new file mode 100644 index 0000000..dee7d56 --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/examples.mustache @@ -0,0 +1,31 @@ + +
    +

    {{_i}}Bootstrap examples{{/i}}

    +

    {{_i}}We've included a few basic examples as starting points for your work with Bootstrap. We encourage folks to iterate on these examples and not simply use them as an end result.{{/i}}

    +
    + + +
      +
    • + + + +

      {{_i}}Basic marketing site{{/i}}

      +

      {{_i}}Featuring a hero unit for a primary message and three supporting elements.{{/i}}

      +
    • +
    • + + + +

      {{_i}}Fluid layout{{/i}}

      +

      {{_i}}Uses our new responsive, fluid grid system to create a seamless liquid layout.{{/i}}

      +
    • +
    • + + + +

      {{_i}}Starter template{{/i}}

      +

      {{_i}}A barebones HTML document with all the Bootstrap CSS and javascript included.{{/i}}

      +
    • +
    diff --git a/test/public/bootstrap/docs/templates/pages/index.mustache b/test/public/bootstrap/docs/templates/pages/index.mustache new file mode 100644 index 0000000..41a89e0 --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/index.mustache @@ -0,0 +1,144 @@ + +
    +
    +

    {{_i}}Bootstrap, from Twitter{{/i}}

    +

    {{_i}}Simple and flexible HTML, CSS, and Javascript for popular user interface components and interactions.{{/i}}

    +

    + {{_i}}View project on GitHub{{/i}} + {{_i}}Download Bootstrap (v2.0.3){{/i}} +

    +
    + + +
    + +
    + +
    +

    {{_i}}Designed for everyone, everywhere.{{/i}}

    + +
    +
    + +

    {{_i}}Built for and by nerds{{/i}}

    +

    {{_i}}Like you, we love building awesome products on the web. We love it so much, we decided to help people just like us do it easier, better, and faster. Bootstrap is built for you.{{/i}}

    +
    +
    + +

    {{_i}}For all skill levels{{/i}}

    +

    {{_i}}Bootstrap is designed to help people of all skill levels—designer or developer, huge nerd or early beginner. Use it as a complete kit or use to start something more complex.{{/i}}

    +
    +
    + +

    {{_i}}Cross-everything{{/i}}

    +

    {{_i}}Originally built with only modern browsers in mind, Bootstrap has evolved to include support for all major browsers (even IE7!) and, with Bootstrap 2, tablets and smartphones, too.{{/i}}

    +
    +
    +
    +
    + +

    {{_i}}12-column grid{{/i}}

    +

    {{_i}}Grid systems aren't everything, but having a durable and flexible one at the core of your work can make development much simpler. Use our built-in grid classes or roll your own.{{/i}}

    +
    +
    + +

    {{_i}}Responsive design{{/i}}

    +

    {{_i}}With Bootstrap 2, we've gone fully responsive. Our components are scaled according to a range of resolutions and devices to provide a consistent experience, no matter what.{{/i}}

    +
    +
    + +

    {{_i}}Styleguide docs{{/i}}

    +

    {{_i}}Unlike other front-end toolkits, Bootstrap was designed first and foremost as a styleguide to document not only our features, but best practices and living, coded examples.{{/i}}

    +
    +
    +
    +
    + +

    {{_i}}Growing library{{/i}}

    +

    {{_i}}Despite being only 10kb (gzipped), Bootstrap is one of the most complete front-end toolkits out there with dozens of fully functional components ready to be put to use.{{/i}}

    +
    +
    + +

    {{_i}}Custom jQuery plugins{{/i}}

    +

    {{_i}}What good is an awesome design component without easy-to-use, proper, and extensible interactions? With Bootstrap, you get custom-built jQuery plugins to bring your projects to life.{{/i}}

    +
    +
    + +

    {{_i}}Built on LESS{{/i}}

    +

    {{_i}}Where vanilla CSS falters, LESS excels. Variables, nesting, operations, and mixins in LESS makes coding CSS faster and more efficient with minimal overhead.{{/i}}

    +
    +
    +
    +
    + +

    HTML5

    +

    {{_i}}Built to support new HTML5 elements and syntax.{{/i}}

    +
    +
    + +

    CSS3

    +

    {{_i}}Progressively enhanced components for ultimate style.{{/i}}

    +
    +
    + +

    {{_i}}Open-source{{/i}}

    +

    {{_i}}Built for and maintained by the community via GitHub.{{/i}}

    +
    +
    + +

    {{_i}}Made at Twitter{{/i}}

    +

    {{_i}}Brought to you by an experienced engineer and designer.{{/i}}

    +
    +
    + +
    + +

    {{_i}}Built with Bootstrap.{{/i}}

    + + + +
    \ No newline at end of file diff --git a/test/public/bootstrap/docs/templates/pages/javascript.mustache b/test/public/bootstrap/docs/templates/pages/javascript.mustache new file mode 100644 index 0000000..1ae3ffa --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/javascript.mustache @@ -0,0 +1,1429 @@ + +
    +

    {{_i}}Javascript for Bootstrap{{/i}}

    +

    {{_i}}Bring Bootstrap's components to life—now with 12 custom jQuery plugins.{{/i}} +

    +
    + + + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    {{_i}}Heads up!{{/i}} {{_i}}All javascript plugins require the latest version of jQuery.{{/i}}
    +
    + + + + +
    + +
    +
    +

    {{_i}}About modals{{/i}}

    +

    {{_i}}A streamlined, but flexible, take on the traditional javascript modal plugin with only the minimum required functionality and smart defaults.{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Static example{{/i}}

    +

    {{_i}}Below is a statically rendered modal.{{/i}}

    + + +

    {{_i}}Live demo{{/i}}

    +

    {{_i}}Toggle a modal via javascript by clicking the button below. It will slide down and fade in from the top of the page.{{/i}}

    + + + {{_i}}Launch demo modal{{/i}} + +
    + +

    {{_i}}Using bootstrap-modal{{/i}}

    +

    {{_i}}Call the modal via javascript:{{/i}}

    +
    $('#myModal').modal(options)
    +

    {{_i}}Options{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}type{{/i}}{{_i}}default{{/i}}{{_i}}description{{/i}}
    {{_i}}backdrop{{/i}}{{_i}}boolean{{/i}}{{_i}}true{{/i}}{{_i}}Includes a modal-backdrop element. Alternatively, specify static for a backdrop which doesn't close the modal on click.{{/i}}
    {{_i}}keyboard{{/i}}{{_i}}boolean{{/i}}{{_i}}true{{/i}}{{_i}}Closes the modal when escape key is pressed{{/i}}
    {{_i}}show{{/i}}{{_i}}boolean{{/i}}{{_i}}true{{/i}}{{_i}}Shows the modal when initialized.{{/i}}
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}You can activate modals on your page easily without having to write a single line of javascript. Just set data-toggle="modal" on a controller element with a data-target="#foo" or href="#foo" which corresponds to a modal element id, and when clicked, it will launch your modal.

    +

    Also, to add options to your modal instance, just include them as additional data attributes on either the control element or the modal markup itself.{{/i}}

    +
    +<a class="btn" data-toggle="modal" href="#myModal" >{{_i}}Launch Modal{{/i}}</a>
    +
    + +
    +<div class="modal" id="myModal">
    +  <div class="modal-header">
    +    <button class="close" data-dismiss="modal">×</button>
    +    <h3>Modal header</h3>
    +  </div>
    +  <div class="modal-body">
    +    <p>{{_i}}One fine body…{{/i}}</p>
    +  </div>
    +  <div class="modal-footer">
    +    <a href="#" class="btn">{{_i}}Close{{/i}}</a>
    +    <a href="#" class="btn btn-primary">{{_i}}Save changes{{/i}}</a>
    +  </div>
    +</div>
    +
    +
    + {{_i}}Heads up!{{/i}} {{_i}}If you want your modal to animate in and out, just add a .fade class to the .modal element (refer to the demo to see this in action) and include bootstrap-transition.js.{{/i}} +
    + Methods{{/i}} +

    .modal({{_i}}options{{/i}})

    +

    {{_i}}Activates your content as a modal. Accepts an optional options object.{{/i}}

    +
    +$('#myModal').modal({
    +  keyboard: false
    +})
    +

    .modal('toggle')

    +

    {{_i}}Manually toggles a modal.{{/i}}

    +
    $('#myModal').modal('toggle')
    +

    .modal('show')

    +

    {{_i}}Manually opens a modal.{{/i}}

    +
    $('#myModal').modal('show')
    +

    .modal('hide')

    +

    {{_i}}Manually hides a modal.{{/i}}

    +
    $('#myModal').modal('hide')
    +

    {{_i}}Events{{/i}}

    +

    {{_i}}Bootstrap's modal class exposes a few events for hooking into modal functionality.{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Event{{/i}}{{_i}}Description{{/i}}
    {{_i}}show{{/i}}{{_i}}This event fires immediately when the show instance method is called.{{/i}}
    {{_i}}shown{{/i}}{{_i}}This event is fired when the modal has been made visible to the user (will wait for css transitions to complete).{{/i}}
    {{_i}}hide{{/i}}{{_i}}This event is fired immediately when the hide instance method has been called.{{/i}}
    {{_i}}hidden{{/i}}{{_i}}This event is fired when the modal has finished being hidden from the user (will wait for css transitions to complete).{{/i}}
    + +
    +$('#myModal').on('hidden', function () {
    +  // {{_i}}do something…{{/i}}
    +})
    +
    +
    +
    + + + + + + + + + +
    + +
    +
    +

    {{_i}}The ScrollSpy plugin is for automatically updating nav targets based on scroll position.{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Example navbar with scrollspy{{/i}}

    +

    {{_i}}Scroll the area below and watch the navigation update. The dropdown sub items will be highlighted as well. Try it!{{/i}}

    + +
    +

    @fat

    +

    + Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat. +

    +

    @mdo

    +

    + Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard. Freegan beard aliqua cupidatat mcsweeney's vero. Cupidatat four loko nisi, ea helvetica nulla carles. Tattooed cosby sweater food truck, mcsweeney's quis non freegan vinyl. Lo-fi wes anderson +1 sartorial. Carles non aesthetic exercitation quis gentrify. Brooklyn adipisicing craft beer vice keytar deserunt. +

    +

    one

    +

    + Occaecat commodo aliqua delectus. Fap craft beer deserunt skateboard ea. Lomo bicycle rights adipisicing banh mi, velit ea sunt next level locavore single-origin coffee in magna veniam. High life id vinyl, echo park consequat quis aliquip banh mi pitchfork. Vero VHS est adipisicing. Consectetur nisi DIY minim messenger bag. Cred ex in, sustainable delectus consectetur fanny pack iphone. +

    +

    two

    +

    + In incididunt echo park, officia deserunt mcsweeney's proident master cleanse thundercats sapiente veniam. Excepteur VHS elit, proident shoreditch +1 biodiesel laborum craft beer. Single-origin coffee wayfarers irure four loko, cupidatat terry richardson master cleanse. Assumenda you probably haven't heard of them art party fanny pack, tattooed nulla cardigan tempor ad. Proident wolf nesciunt sartorial keffiyeh eu banh mi sustainable. Elit wolf voluptate, lo-fi ea portland before they sold out four loko. Locavore enim nostrud mlkshk brooklyn nesciunt. +

    +

    three

    +

    + Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat. +

    +

    Keytar twee blog, culpa messenger bag marfa whatever delectus food truck. Sapiente synth id assumenda. Locavore sed helvetica cliche irony, thundercats you probably haven't heard of them consequat hoodie gluten-free lo-fi fap aliquip. Labore elit placeat before they sold out, terry richardson proident brunch nesciunt quis cosby sweater pariatur keffiyeh ut helvetica artisan. Cardigan craft beer seitan readymade velit. VHS chambray laboris tempor veniam. Anim mollit minim commodo ullamco thundercats. +

    +
    +
    +

    {{_i}}Using bootstrap-scrollspy.js{{/i}}

    +

    {{_i}}Call the scrollspy via javascript:{{/i}}

    +
    $('#navbar').scrollspy()
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}To easily add scrollspy behavior to your topbar navigation, just add data-spy="scroll" to the element you want to spy on (most typically this would be the body).{{/i}}

    +
    <body data-spy="scroll" >...</body>
    +
    + {{_i}}Heads up!{{/i}} + {{_i}}Navbar links must have resolvable id targets. For example, a <a href="#home">home</a> must correspond to something in the dom like <div id="home"></div>.{{/i}} +
    +

    {{_i}}Methods{{/i}}

    +

    .scrollspy('refresh')

    +

    {{_i}}When using scrollspy in conjunction with adding or removing of elements from the DOM, you'll need to call the refresh method like so:{{/i}}

    +
    +$('[data-spy="scroll"]').each(function () {
    +  var $spy = $(this).scrollspy('refresh')
    +});
    +
    +

    {{_i}}Options{{/i}}

    + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}type{{/i}}{{_i}}default{{/i}}{{_i}}description{{/i}}
    {{_i}}offset{{/i}}{{_i}}number{{/i}}{{_i}}10{{/i}}{{_i}}Pixels to offset from top when calculating position of scroll.{{/i}}
    +

    {{_i}}Events{{/i}}

    + + + + + + + + + + + + + +
    {{_i}}Event{{/i}}{{_i}}Description{{/i}}
    {{_i}}activate{{/i}}{{_i}}This event fires whenever a new item becomes activated by the scrollspy.{{/i}}
    +
    +
    +
    + + + + +
    + +
    +
    +

    {{_i}}This plugin adds quick, dynamic tab and pill functionality for transitioning through local content.{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Example tabs{{/i}}

    +

    {{_i}}Click the tabs below to toggle between hidden panes, even via dropdown menus.{{/i}}

    + +
    +
    +

    Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.

    +
    +
    +

    Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.

    +
    + + +
    +
    +

    {{_i}}Using bootstrap-tab.js{{/i}}

    +

    {{_i}}Enable tabbable tabs via javascript (each tab needs to be activated individually):{{/i}}

    +
    +$('#myTab a').click(function (e) {
    +  e.preventDefault();
    +  $(this).tab('show');
    +})
    +

    {{_i}}You can activate individual tabs in several ways:{{/i}}

    +
    +$('#myTab a[href="#profile"]').tab('show'); // Select tab by name
    +$('#myTab a:first').tab('show'); // Select first tab
    +$('#myTab a:last').tab('show'); // Select last tab
    +$('#myTab li:eq(2) a').tab('show'); // Select third tab (0-indexed)
    +
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}You can activate a tab or pill navigation without writing any javascript by simply specifying data-toggle="tab" or data-toggle="pill" on an element. Adding the nav and nav-tabs classes to the tab ul will apply the bootstrap tab styling.{{/i}}

    +
    +<ul class="nav nav-tabs">
    +  <li><a href="#home" data-toggle="tab">{{_i}}Home{{/i}}</a></li>
    +  <li><a href="#profile" data-toggle="tab">{{_i}}Profile{{/i}}</a></li>
    +  <li><a href="#messages" data-toggle="tab">{{_i}}Messages{{/i}}</a></li>
    +  <li><a href="#settings" data-toggle="tab">{{_i}}Settings{{/i}}</a></li>
    +</ul>
    +

    {{_i}}Methods{{/i}}

    +

    $().tab

    +

    + {{_i}}Activates a tab element and content container. Tab should have either a data-target or an href targeting a container node in the DOM.{{/i}} +

    +
    +<ul class="nav nav-tabs" id="myTab">
    +  <li class="active"><a href="#home">{{_i}}Home{{/i}}</a></li>
    +  <li><a href="#profile">{{_i}}Profile{{/i}}</a></li>
    +  <li><a href="#messages">{{_i}}Messages{{/i}}</a></li>
    +  <li><a href="#settings">{{_i}}Settings{{/i}}</a></li>
    +</ul>
    +
    +<div class="tab-content">
    +  <div class="tab-pane active" id="home">...</div>
    +  <div class="tab-pane" id="profile">...</div>
    +  <div class="tab-pane" id="messages">...</div>
    +  <div class="tab-pane" id="settings">...</div>
    +</div>
    +
    +<script>
    +  $(function () {
    +    $('#myTab a:last').tab('show');
    +  })
    +</script>
    +

    {{_i}}Events{{/i}}

    + + + + + + + + + + + + + + + + + +
    {{_i}}Event{{/i}}{{_i}}Description{{/i}}
    {{_i}}show{{/i}}{{_i}}This event fires on tab show, but before the new tab has been shown. Use event.target and event.relatedTarget to target the active tab and the previous active tab (if available) respectively.{{/i}}
    {{_i}}shown{{/i}}{{_i}}This event fires on tab show after a tab has been shown. Use event.target and event.relatedTarget to target the active tab and the previous active tab (if available) respectively.{{/i}}
    + +
    +$('a[data-toggle="tab"]').on('shown', function (e) {
    +  e.target // activated tab
    +  e.relatedTarget // previous tab
    +})
    +
    +
    +
    + + + +
    + +
    +
    +

    {{_i}}About Tooltips{{/i}}

    +

    {{_i}}Inspired by the excellent jQuery.tipsy plugin written by Jason Frame; Tooltips are an updated version, which don't rely on images, use css3 for animations, and data-attributes for local title storage.{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Example use of Tooltips{{/i}}

    +

    {{_i}}Hover over the links below to see tooltips:{{/i}}

    +
    +

    {{_i}}Tight pants next level keffiyeh you probably haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel have a terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan whatever keytar, scenester farm-to-table banksy Austin twitter handle freegan cred raw denim single-origin coffee viral.{{/i}} +

    +
    +
    +

    {{_i}}Using{{/i}} bootstrap-tooltip.js

    +

    {{_i}}Trigger the tooltip via javascript:{{/i}}

    +
    $('#example').tooltip({{_i}}options{{/i}})
    +

    {{_i}}Options{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}type{{/i}}{{_i}}default{{/i}}{{_i}}description{{/i}}
    {{_i}}animation{{/i}}{{_i}}boolean{{/i}}true{{_i}}apply a css fade transition to the tooltip{{/i}}
    {{_i}}placement{{/i}}{{_i}}string|function{{/i}}'top'{{_i}}how to position the tooltip{{/i}} - top | bottom | left | right
    {{_i}}selector{{/i}}{{_i}}string{{/i}}false{{_i}}If a selector is provided, tooltip objects will be delegated to the specified targets.{{/i}}
    {{_i}}title{{/i}}{{_i}}string | function{{/i}}''{{_i}}default title value if `title` tag isn't present{{/i}}
    {{_i}}trigger{{/i}}{{_i}}string{{/i}}'hover'{{_i}}how tooltip is triggered{{/i}} - hover | focus | manual
    {{_i}}delay{{/i}}{{_i}}number | object{{/i}}0 +

    {{_i}}delay showing and hiding the tooltip (ms) - does not apply to manual trigger type{{/i}}

    +

    {{_i}}If a number is supplied, delay is applied to both hide/show{{/i}}

    +

    {{_i}}Object structure is: delay: { show: 500, hide: 100 }{{/i}}

    +
    +
    + {{_i}}Heads up!{{/i}} + {{_i}}Options for individual tooltips can alternatively be specified through the use of data attributes.{{/i}} +
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}For performance reasons, the Tooltip and Popover data-apis are opt in. If you would like to use them just specify a selector option.{{/i}}

    +
    +<a href="#" rel="tooltip" title="{{_i}}first tooltip{{/i}}">{{_i}}hover over me{{/i}}</a>
    +
    +

    {{_i}}Methods{{/i}}

    +

    $().tooltip({{_i}}options{{/i}})

    +

    {{_i}}Attaches a tooltip handler to an element collection.{{/i}}

    +

    .tooltip('show')

    +

    {{_i}}Reveals an element's tooltip.{{/i}}

    +
    $('#element').tooltip('show')
    +

    .tooltip('hide')

    +

    {{_i}}Hides an element's tooltip.{{/i}}

    +
    $('#element').tooltip('hide')
    +

    .tooltip('toggle')

    +

    {{_i}}Toggles an element's tooltip.{{/i}}

    +
    $('#element').tooltip('toggle')
    +
    +
    +
    + + + + +
    + +
    +
    +

    {{_i}}About popovers{{/i}}

    +

    {{_i}}Add small overlays of content, like those on the iPad, to any element for housing secondary information.{{/i}}

    +

    * {{_i}}Requires Tooltip to be included{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Example hover popover{{/i}}

    +

    {{_i}}Hover over the button to trigger the popover.{{/i}}

    + +
    +

    {{_i}}Using bootstrap-popover.js{{/i}}

    +

    {{_i}}Enable popovers via javascript:{{/i}}

    +
    $('#example').popover({{_i}}options{{/i}})
    +

    {{_i}}Options{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}type{{/i}}{{_i}}default{{/i}}{{_i}}description{{/i}}
    {{_i}}animation{{/i}}{{_i}}boolean{{/i}}true{{_i}}apply a css fade transition to the tooltip{{/i}}
    {{_i}}placement{{/i}}{{_i}}string|function{{/i}}'right'{{_i}}how to position the popover{{/i}} - top | bottom | left | right
    {{_i}}selector{{/i}}{{_i}}string{{/i}}false{{_i}}if a selector is provided, tooltip objects will be delegated to the specified targets{{/i}}
    {{_i}}trigger{{/i}}{{_i}}string{{/i}}'hover'{{_i}}how tooltip is triggered{{/i}} - hover | focus | manual
    {{_i}}title{{/i}}{{_i}}string | function{{/i}}''{{_i}}default title value if `title` attribute isn't present{{/i}}
    {{_i}}content{{/i}}{{_i}}string | function{{/i}}''{{_i}}default content value if `data-content` attribute isn't present{{/i}}
    {{_i}}delay{{/i}}{{_i}}number | object{{/i}}0 +

    {{_i}}delay showing and hiding the popover (ms) - does not apply to manual trigger type{{/i}}

    +

    {{_i}}If a number is supplied, delay is applied to both hide/show{{/i}}

    +

    {{_i}}Object structure is: delay: { show: 500, hide: 100 }{{/i}}

    +
    +
    + {{_i}}Heads up!{{/i}} + {{_i}}Options for individual popovers can alternatively be specified through the use of data attributes.{{/i}} +
    +

    {{_i}}Markup{{/i}}

    +

    + {{_i}}For performance reasons, the Tooltip and Popover data-apis are opt in. If you would like to use them just specify a selector option.{{/i}} +

    +

    {{_i}}Methods{{/i}}

    +

    $().popover({{_i}}options{{/i}})

    +

    {{_i}}Initializes popovers for an element collection.{{/i}}

    +

    .popover('show')

    +

    {{_i}}Reveals an elements popover.{{/i}}

    +
    $('#element').popover('show')
    +

    .popover('hide')

    +

    {{_i}}Hides an elements popover.{{/i}}

    +
    $('#element').popover('hide')
    +

    .popover('toggle')

    +

    {{_i}}Toggles an elements popover.{{/i}}

    +
    $('#element').popover('toggle')
    +
    +
    +
    + + + + +
    + +
    +
    +

    {{_i}}About alerts{{/i}}

    +

    {{_i}}The alert plugin is a tiny class for adding close functionality to alerts.{{/i}}

    + {{_i}}Download{{/i}} +
    +
    +

    {{_i}}Example alerts{{/i}}

    +

    {{_i}}The alerts plugin works on regular alert messages, and block messages.{{/i}}

    +
    + + {{_i}}Holy guacamole!{{/i}} {{_i}}Best check yo self, you're not looking too good.{{/i}} +
    +
    + +

    {{_i}}Oh snap! You got an error!{{/i}}

    +

    {{_i}}Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.{{/i}}

    +

    + {{_i}}Take this action{{/i}} {{_i}}Or do this{{/i}} +

    +
    +
    +

    {{_i}}Using bootstrap-alert.js{{/i}}

    +

    {{_i}}Enable dismissal of an alert via javascript:{{/i}}

    +
    $(".alert").alert()
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}Just add data-dismiss="alert" to your close button to automatically give an alert close functionality.{{/i}}

    +
    <a class="close" data-dismiss="alert" href="#">&times;</a>
    +

    {{_i}}Methods{{/i}}

    +

    $().alert()

    +

    {{_i}}Wraps all alerts with close functionality. To have your alerts animate out when closed, make sure they have the .fade and .in class already applied to them.{{/i}}

    +

    .alert('close')

    +

    {{_i}}Closes an alert.{{/i}}

    +
    $(".alert").alert('close')
    +

    {{_i}}Events{{/i}}

    +

    {{_i}}Bootstrap's alert class exposes a few events for hooking into alert functionality.{{/i}}

    + + + + + + + + + + + + + + + + + +
    {{_i}}Event{{/i}}{{_i}}Description{{/i}}
    {{_i}}close{{/i}}{{_i}}This event fires immediately when the close instance method is called.{{/i}}
    {{_i}}closed{{/i}}{{_i}}This event is fired when the alert has been closed (will wait for css transitions to complete).{{/i}}
    +
    +$('#my-alert').bind('closed', function () {
    +  // {{_i}}do something…{{/i}}
    +})
    +
    +
    +
    + + + + +
    + +
    +
    +

    {{_i}}About{{/i}}

    +

    {{_i}}Do more with buttons. Control button states or create groups of buttons for more components like toolbars.{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Example uses{{/i}}

    +

    {{_i}}Use the buttons plugin for states and toggles.{{/i}}

    + + + + + + + + + + + + + + + + + + + +
    {{_i}}Stateful{{/i}} + +
    {{_i}}Single toggle{{/i}} + +
    {{_i}}Checkbox{{/i}} +
    + + + +
    +
    {{_i}}Radio{{/i}} +
    + + + +
    +
    +
    +

    {{_i}}Using bootstrap-button.js{{/i}}

    +

    {{_i}}Enable buttons via javascript:{{/i}}

    +
    $('.nav-tabs').button()
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}Data attributes are integral to the button plugin. Check out the example code below for the various markup types.{{/i}}

    +
    +<!-- {{_i}}Add data-toggle="button" to activate toggling on a single button{{/i}} -->
    +<button class="btn" data-toggle="button">Single Toggle</button>
    +
    +<!-- {{_i}}Add data-toggle="buttons-checkbox" for checkbox style toggling on btn-group{{/i}} -->
    +<div class="btn-group" data-toggle="buttons-checkbox">
    +  <button class="btn">Left</button>
    +  <button class="btn">Middle</button>
    +  <button class="btn">Right</button>
    +</div>
    +
    +<!-- {{_i}}Add data-toggle="buttons-radio" for radio style toggling on btn-group{{/i}} -->
    +<div class="btn-group" data-toggle="buttons-radio">
    +  <button class="btn">Left</button>
    +  <button class="btn">Middle</button>
    +  <button class="btn">Right</button>
    +</div>
    +
    +

    {{_i}}Methods{{/i}}

    +

    $().button('toggle')

    +

    {{_i}}Toggles push state. Gives the button the appearance that it has been activated.{{/i}}

    +
    + {{_i}}Heads up!{{/i}} + {{_i}}You can enable auto toggling of a button by using the data-toggle attribute.{{/i}} +
    +
    <button class="btn" data-toggle="button" >…</button>
    +

    $().button('loading')

    +

    {{_i}}Sets button state to loading - disables button and swaps text to loading text. Loading text should be defined on the button element using the data attribute data-loading-text.{{/i}} +

    +
    <button class="btn" data-loading-text="loading stuff..." >...</button>
    +
    + {{_i}}Heads up!{{/i}} + {{_i}}Firefox persists the disabled state across page loads. A workaround for this is to use autocomplete="off".{{/i}} +
    +

    $().button('reset')

    +

    {{_i}}Resets button state - swaps text to original text.{{/i}}

    +

    $().button(string)

    +

    {{_i}}Resets button state - swaps text to any data defined text state.{{/i}}

    +
    <button class="btn" data-complete-text="finished!" >...</button>
    +<script>
    +  $('.btn').button('complete')
    +</script>
    +
    +
    +
    + + + + +
    + +
    +
    +

    {{_i}}About{{/i}}

    +

    {{_i}}Get base styles and flexible support for collapsible components like accordions and navigation.{{/i}}

    + {{_i}}Download file{{/i}} +

    * {{_i}}Requires the Transitions plugin to be included.{{/i}}

    +
    +
    +

    {{_i}}Example accordion{{/i}}

    +

    {{_i}}Using the collapse plugin, we built a simple accordion style widget:{{/i}}

    + +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + +
    +
    + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. +
    +
    +
    +
    + + +
    +

    {{_i}}Using bootstrap-collapse.js{{/i}}

    +

    {{_i}}Enable via javascript:{{/i}}

    +
    $(".collapse").collapse()
    +

    {{_i}}Options{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}type{{/i}}{{_i}}default{{/i}}{{_i}}description{{/i}}
    {{_i}}parent{{/i}}{{_i}}selector{{/i}}false{{_i}}If selector then all collapsible elements under the specified parent will be closed when this collapsible item is shown. (similar to traditional accordion behavior){{/i}}
    {{_i}}toggle{{/i}}{{_i}}boolean{{/i}}true{{_i}}Toggles the collapsible element on invocation{{/i}}
    +

    {{_i}}Markup{{/i}}

    +

    {{_i}}Just add data-toggle="collapse" and a data-target to element to automatically assign control of a collapsible element. The data-target attribute accepts a css selector to apply the collapse to. Be sure to add the class collapse to the collapsible element. If you'd like it to default open, add the additional class in.{{/i}}

    +
    +<button class="btn btn-danger" data-toggle="collapse" data-target="#demo">
    +  {{_i}}simple collapsible{{/i}}
    +</button>
    +
    +<div id="demo" class="collapse in"> … </div>
    +
    + {{_i}}Heads up!{{/i}} + {{_i}}To add accordion-like group management to a collapsible control, add the data attribute data-parent="#selector". Refer to the demo to see this in action.{{/i}} +
    +

    {{_i}}Methods{{/i}}

    +

    .collapse({{_i}}options{{/i}})

    +

    {{_i}}Activates your content as a collapsible element. Accepts an optional options object.{{/i}} +

    +$('#myCollapsible').collapse({
    +  toggle: false
    +})
    +

    .collapse('toggle')

    +

    {{_i}}Toggles a collapsible element to shown or hidden.{{/i}}

    +

    .collapse('show')

    +

    {{_i}}Shows a collapsible element.{{/i}}

    +

    .collapse('hide')

    +

    {{_i}}Hides a collapsible element.{{/i}}

    +

    {{_i}}Events{{/i}}

    +

    + {{_i}}Bootstrap's collapse class exposes a few events for hooking into collapse functionality.{{/i}} +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Event{{/i}}{{_i}}Description{{/i}}
    {{_i}}show{{/i}}{{_i}}This event fires immediately when the show instance method is called.{{/i}}
    {{_i}}shown{{/i}}{{_i}}This event is fired when a collapse element has been made visible to the user (will wait for css transitions to complete).{{/i}}
    {{_i}}hide{{/i}} + {{_i}}This event is fired immediately when the hide method has been called.{{/i}} +
    {{_i}}hidden{{/i}}{{_i}}This event is fired when a collapse element has been hidden from the user (will wait for css transitions to complete).{{/i}}
    + +
    +$('#myCollapsible').on('hidden', function () {
    +  // {{_i}}do something…{{/i}}
    +})
    +
    +
    +
    + + + + + + + + + +
    + +
    +
    +

    {{_i}}About{{/i}}

    +

    {{_i}}A basic, easily extended plugin for quickly creating elegant typeaheads with any form text input.{{/i}}

    + {{_i}}Download file{{/i}} +
    +
    +

    {{_i}}Example{{/i}}

    +

    {{_i}}Start typing in the field below to show the typeahead results.{{/i}}

    +
    + +
    +
    +

    {{_i}}Using bootstrap-typeahead.js{{/i}}

    +

    {{_i}}Call the typeahead via javascript:{{/i}}

    +
    $('.typeahead').typeahead()
    +

    {{_i}}Options{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Name{{/i}}{{_i}}type{{/i}}{{_i}}default{{/i}}{{_i}}description{{/i}}
    {{_i}}source{{/i}}{{_i}}array{{/i}}[ ]{{_i}}The data source to query against.{{/i}}
    {{_i}}items{{/i}}{{_i}}number{{/i}}8{{_i}}The max number of items to display in the dropdown.{{/i}}
    {{_i}}matcher{{/i}}{{_i}}function{{/i}}{{_i}}case insensitive{{/i}}{{_i}}The method used to determine if a query matches an item. Accepts a single argument, the item against which to test the query. Access the current query with this.query. Return a boolean true if query is a match.{{/i}}
    {{_i}}sorter{{/i}}{{_i}}function{{/i}}{{_i}}exact match,
    case sensitive,
    case insensitive{{/i}}
    {{_i}}Method used to sort autocomplete results. Accepts a single argument items and has the scope of the typeahead instance. Reference the current query with this.query.{{/i}}
    {{_i}}highlighter{{/i}}{{_i}}function{{/i}}{{_i}}highlights all default matches{{/i}}{{_i}}Method used to highlight autocomplete results. Accepts a single argument item and has the scope of the typeahead instance. Should return html.{{/i}}
    + +

    {{_i}}Markup{{/i}}

    +

    {{_i}}Add data attributes to register an element with typeahead functionality.{{/i}}

    +
    +<input type="text" data-provide="typeahead">
    +
    +

    {{_i}}Methods{{/i}}

    +

    .typeahead({{_i}}options{{/i}})

    +

    {{_i}}Initializes an input with a typeahead.{{/i}}

    +
    +
    +
    \ No newline at end of file diff --git a/test/public/bootstrap/docs/templates/pages/less.mustache b/test/public/bootstrap/docs/templates/pages/less.mustache new file mode 100644 index 0000000..7698dd2 --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/less.mustache @@ -0,0 +1,938 @@ + +
    +

    {{_i}}Using LESS with Bootstrap{{/i}}

    +

    {{_i}}Customize and extend Bootstrap with LESS, a CSS preprocessor, to take advantage of the variables, mixins, and more used to build Bootstrap's CSS.{{/i}}

    + +
    + + + + +
    + +
    +
    +

    {{_i}}Why LESS?{{/i}}

    +

    {{_i}}Bootstrap is made with LESS at its core, a dynamic stylesheet language created by our good friend, Alexis Sellier. It makes developing systems-based CSS faster, easier, and more fun.{{/i}}

    +
    +
    +

    {{_i}}What's included?{{/i}}

    +

    {{_i}}As an extension of CSS, LESS includes variables, mixins for reusable snippets of code, operations for simple math, nesting, and even color functions.{{/i}}

    +
    +
    +

    {{_i}}Learn more{{/i}}

    + LESS CSS +

    {{_i}}Visit the official website at http://lesscss.org to learn more.{{/i}}

    +
    +
    +
    +
    +

    {{_i}}Variables{{/i}}

    +

    {{_i}}Managing colors and pixel values in CSS can be a bit of a pain, usually full of copy and paste. Not with LESS though—assign colors or pixel values as variables and change them once.{{/i}}

    +
    +
    +

    {{_i}}Mixins{{/i}}

    +

    {{_i}}Those three border-radius declarations you need to make in regular ol' CSS? Now they're down to one line with the help of mixins, snippets of code you can reuse anywhere.{{/i}}

    +
    +
    +

    {{_i}}Operations{{/i}}

    +

    {{_i}}Make your grid, leading, and more super flexible by doing the math on the fly with operations. Multiply, divide, add, and subtract your way to CSS sanity.{{/i}}

    +
    +
    +
    + + + + +
    + + +
    +
    +

    {{_i}}Scaffolding and links{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @bodyBackground@white{{_i}}Page background color{{/i}}
    @textColor@grayDark{{_i}}Default text color for entire body, headings, and more{{/i}}
    @linkColor#08c{{_i}}Default link text color{{/i}}
    @linkColorHoverdarken(@linkColor, 15%){{_i}}Default link text hover color{{/i}}
    +

    {{_i}}Grid system{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + +
    @gridColumns12
    @gridColumnWidth60px
    @gridGutterWidth20px
    @fluidGridColumnWidth6.382978723%
    @fluidGridGutterWidth2.127659574%
    +

    {{_i}}Typography{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @sansFontFamily"Helvetica Neue", Helvetica, Arial, sans-serif
    @serifFontFamilyGeorgia, "Times New Roman", Times, serif
    @monoFontFamilyMenlo, Monaco, "Courier New", monospace
    @baseFontSize13pxMust be pixels
    @baseFontFamily@sansFontFamily
    @baseLineHeight18pxMust be pixels
    @altFontFamily@serifFontFamily
    @headingsFontFamilyinherit
    @headingsFontWeightbold
    @headingsColorinherit
    +

    {{_i}}Tables{{/i}}

    + + + + + + + + + + + + + + + + + + + +
    @tableBackgroundtransparent
    @tableBackgroundAccent#f9f9f9
    @tableBackgroundHover#f5f5f5
    @tableBorderddd
    +
    +
    +

    {{_i}}Grayscale colors{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @black#000
    @grayDarker#222
    @grayDark#333
    @gray#555
    @grayLight#999
    @grayLighter#eee
    @white#fff
    +

    {{_i}}Accent colors{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @blue#049cdb
    @green#46a546
    @red#9d261d
    @yellow#ffc40d
    @orange#f89406
    @pink#c3325f
    @purple#7a43b6
    +
    +
    + +

    {{_i}}Components{{/i}}

    +
    +
    +

    {{_i}}Buttons{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @btnBackground@white
    @btnBackgroundHighlightdarken(@white, 10%)
    @btnBorderdarken(@white, 20%)
    @btnPrimaryBackground@linkColor
    @btnPrimaryBackgroundHighlightspin(@btnPrimaryBackground, 15%)
    @btnInfoBackground#5bc0de
    @btnInfoBackgroundHighlight#2f96b4
    @btnSuccessBackground#62c462
    @btnSuccessBackgroundHighlight51a351
    @btnWarningBackgroundlighten(@orange, 15%)
    @btnWarningBackgroundHighlight@orange
    @btnDangerBackground#ee5f5b
    @btnDangerBackgroundHighlight#bd362f
    @btnInverseBackground@gray
    @btnInverseBackgroundHighlight@grayDarker
    +

    {{_i}}Forms{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @placeholderText@grayLight
    @inputBackground@white
    @inputBorder#ccc
    @inputBorderRadius3px
    @inputDisabledBackground@grayLighter
    @formActionsBackground#f5f5f5
    +

    {{_i}}Form states and alerts{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @warningText#c09853
    @warningBackground#f3edd2
    @errorText#b94a48
    @errorBackground#f2dede
    @successText#468847
    @successBackground#dff0d8
    @infoText#3a87ad
    @infoBackground#d9edf7
    +
    +
    +

    {{_i}}Navbar{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    @navbarHeight40px
    @navbarBackground@grayDarker
    @navbarBackgroundHighlight@grayDark
    @navbarText@grayLight
    @navbarLinkColor@grayLight
    @navbarLinkColorHover@white
    @navbarLinkColorActive@navbarLinkColorHover
    @navbarLinkBackgroundHovertransparent
    @navbarLinkBackgroundActive@navbarBackground
    @navbarSearchBackgroundlighten(@navbarBackground, 25%)
    @navbarSearchBackgroundFocus@white
    @navbarSearchBorderdarken(@navbarSearchBackground, 30%)
    @navbarSearchPlaceholderColor#ccc
    @navbarBrandColor@navbarLinkColor
    +

    {{_i}}Dropdowns{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + +
    @dropdownBackground@white
    @dropdownBorderrgba(0,0,0,.2)
    @dropdownLinkColor@grayDark
    @dropdownLinkColorHover@white
    @dropdownLinkBackgroundHover@linkColor
    +

    {{_i}}Hero unit{{/i}}

    + + + + + + + + + + + + + + + + + + +
    @heroUnitBackground@grayLighter
    @heroUnitHeadingColorinherit
    @heroUnitLeadColorinhereit
    +
    +
    + +
    + + + + +
    + +

    {{_i}}About mixins{{/i}}

    +
    +
    +

    {{_i}}Basic mixins{{/i}}

    +

    {{_i}}A basic mixin is essentially an include or a partial for a snippet of CSS. They're written just like a CSS class and can be called anywhere.{{/i}}

    +
    +.element {
    +  .clearfix();
    +}
    +
    +
    +
    +

    {{_i}}Parametric mixins{{/i}}

    +

    {{_i}}A parametric mixin is just like a basic mixin, but it also accepts parameters (hence the name) with optional default values.{{/i}}

    +
    +.element {
    +  .border-radius(4px);
    +}
    +
    +
    +
    +

    {{_i}}Easily add your own{{/i}}

    +

    {{_i}}Nearly all of Bootstrap's mixins are stored in mixins.less, a wonderful utility .less file that enables you to use a mixin in any of the .less files in the toolkit.{{/i}}

    +

    {{_i}}So, go ahead and use the existing ones or feel free to add your own as you need.{{/i}}

    +
    +
    +

    {{_i}}Included mixins{{/i}}

    +

    {{_i}}Utilities{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Mixin{{/i}}{{_i}}Parameters{{/i}}{{_i}}Usage{{/i}}
    .clearfix()none{{_i}}Add to any parent to clear floats within{{/i}}
    .tab-focus()none{{_i}}Apply the Webkit focus style and round Firefox outline{{/i}}
    .center-block()none{{_i}}Auto center a block-level element using margin: auto{{/i}}
    .ie7-inline-block()none{{_i}}Use in addition to regular display: inline-block to get IE7 support{{/i}}
    .size()@height @width{{_i}}Quickly set the height and width on one line{{/i}}
    .square()@size{{_i}}Builds on .size() to set the width and height as same value{{/i}}
    .opacity()@opacity{{_i}}Set, in whole numbers, the opacity percentage (e.g., "50" or "75"){{/i}}
    +

    Forms

    + + + + + + + + + + + + + + + +
    {{_i}}Mixin{{/i}}{{_i}}Parameters{{/i}}{{_i}}Usage{{/i}}
    .placeholder()@color: @placeholderText{{_i}}Set the placeholder text color for inputs{{/i}}
    +

    Typography

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Mixin{{/i}}{{_i}}Parameters{{/i}}{{_i}}Usage{{/i}}
    #font > #family > .serif()none{{_i}}Make an element use a serif font stack{{/i}}
    #font > #family > .sans-serif()none{{_i}}Make an element use a sans-serif font stack{{/i}}
    #font > #family > .monospace()none{{_i}}Make an element use a monospace font stack{{/i}}
    #font > .shorthand()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight{{_i}}Easily set font size, weight, and leading{{/i}}
    #font > .serif()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight{{_i}}Set font family to serif, and control size, weight, and leading{{/i}}
    #font > .sans-serif()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight{{_i}}Set font family to sans-serif, and control size, weight, and leading{{/i}}
    #font > .monospace()@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight{{_i}}Set font family to monospace, and control size, weight, and leading{{/i}}
    +

    Grid system

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Mixin{{/i}}{{_i}}Parameters{{/i}}{{_i}}Usage{{/i}}
    .container-fixed()none{{_i}}Create a horizontally centered container for holding your content{{/i}}
    #grid > .core()@gridColumnWidth, @gridGutterWidth{{_i}}Generate a pixel grid system (container, row, and columns) with n columns and x pixel wide gutter{{/i}}
    #grid > .fluid()@fluidGridColumnWidth, @fluidGridGutterWidth{{_i}}Generate a precent grid system with n columns and x % wide gutter{{/i}}
    #grid > .input()@gridColumnWidth, @gridGutterWidth{{_i}}Generate the pixel grid system for input elements, accounting for padding and borders{{/i}}
    .makeColumn@columns: 1, @offset: 0{{_i}}Turn any div into a grid column without the .span* classes{{/i}}
    +

    {{_i}}CSS3 properties{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Mixin{{/i}}{{_i}}Parameters{{/i}}{{_i}}Usage{{/i}}
    .border-radius()@radius{{_i}}Round the corners of an element. Can be a single value or four space-separated values{{/i}}
    .box-shadow()@shadow{{_i}}Add a drop shadow to an element{{/i}}
    .transition()@transition{{_i}}Add CSS3 transition effect (e.g., all .2s linear){{/i}}
    .rotate()@degrees{{_i}}Rotate an element n degrees{{/i}}
    .scale()@ratio{{_i}}Scale an element to n times its original size{{/i}}
    .translate()@x, @y{{_i}}Move an element on the x and y planes{{/i}}
    .background-clip()@clip{{_i}}Crop the background of an element (useful for border-radius){{/i}}
    .background-size()@size{{_i}}Control the size of background images via CSS3{{/i}}
    .box-sizing()@boxmodel{{_i}}Change the box model for an element (e.g., border-box for a full-width input){{/i}}
    .user-select()@select{{_i}}Control cursor selection of text on a page{{/i}}
    .backface-visibility()@visibility: visible{{_i}}Prevent flickering of content when using CSS 3D transforms{{/i}}
    .resizable()@direction: both{{_i}}Make any element resizable on the right and bottom{{/i}}
    .content-columns()@columnCount, @columnGap: @gridGutterWidth{{_i}}Make the content of any element use CSS3 columns{{/i}}
    +

    {{_i}}Backgrounds and gradients{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Mixin{{/i}}{{_i}}Parameters{{/i}}{{_i}}Usage{{/i}}
    #translucent > .background()@color: @white, @alpha: 1{{_i}}Give an element a translucent background color{{/i}}
    #translucent > .border()@color: @white, @alpha: 1{{_i}}Give an element a translucent border color{{/i}}
    #gradient > .vertical()@startColor, @endColor{{_i}}Create a cross-browser vertical background gradient{{/i}}
    #gradient > .horizontal()@startColor, @endColor{{_i}}Create a cross-browser horizontal background gradient{{/i}}
    #gradient > .directional()@startColor, @endColor, @deg{{_i}}Create a cross-browser directional background gradient{{/i}}
    #gradient > .vertical-three-colors()@startColor, @midColor, @colorStop, @endColor{{_i}}Create a cross-browser three-color background gradient{{/i}}
    #gradient > .radial()@innerColor, @outerColor{{_i}}Create a cross-browser radial background gradient{{/i}}
    #gradient > .striped()@color, @angle{{_i}}Create a cross-browser striped background gradient{{/i}}
    #gradientBar()@primaryColor, @secondaryColor{{_i}}Used for buttons to assign a gradient and slightly darker border{{/i}}
    +
    + + + + +
    + +
    + {{_i}}Note: If you're submitting a pull request to GitHub with modified CSS, you must recompile the CSS via any of these methods.{{/i}} +
    +

    {{_i}}Tools for compiling{{/i}}

    +
    +
    +

    {{_i}}Node with makefile{{/i}}

    +

    {{_i}}Install the LESS command line compiler and uglify-js globally with npm by running the following command:{{/i}}

    +
    $ npm install -g less uglify-js
    +

    {{_i}}Once installed just run make from the root of your bootstrap directory and you're all set.{{/i}}

    +

    {{_i}}Additionally, if you have watchr installed, you may run make watch to have bootstrap automatically rebuilt every time you edit a file in the bootstrap lib (this isn't required, just a convenience method).{{/i}}

    +
    +
    +

    {{_i}}Command line{{/i}}

    +

    {{_i}}Install the LESS command line tool via Node and run the following command:{{/i}}

    +
    $ lessc ./less/bootstrap.less > bootstrap.css
    +

    {{_i}}Be sure to include --compress in that command if you're trying to save some bytes!{{/i}}

    +
    +
    +

    {{_i}}Javascript{{/i}}

    +

    {{_i}}Download the latest Less.js and include the path to it (and Bootstrap) in the <head>.{{/i}}

    +
    +<link rel="stylesheet/less" href="/path/to/bootstrap.less">
    +<script src="/path/to/less.js"></script>
    +
    +

    {{_i}}To recompile the .less files, just save them and reload your page. Less.js compiles them and stores them in local storage.{{/i}}

    +
    +
    +
    +
    +

    {{_i}}Unofficial Mac app{{/i}}

    +

    {{_i}}The unofficial Mac app watches directories of .less files and compiles the code to local files after every save of a watched .less file.{{/i}}

    +

    {{_i}}If you like, you can toggle preferences in the app for automatic minifying and which directory the compiled files end up in.{{/i}}

    +
    +
    +

    {{_i}}More Mac apps{{/i}}

    +

    Crunch

    +

    {{_i}}Crunch is a great looking LESS editor and compiler built on Adobe Air.{{/i}}

    +

    CodeKit

    +

    {{_i}}Created by the same guy as the unofficial Mac app, CodeKit is a Mac app that compiles LESS, SASS, Stylus, and CoffeeScript.{{/i}}

    +

    Simpless

    +

    {{_i}}Mac, Linux, and PC app for drag and drop compiling of LESS files. Plus, the source code is on GitHub.{{/i}}

    +
    +
    +
    diff --git a/test/public/bootstrap/docs/templates/pages/scaffolding.mustache b/test/public/bootstrap/docs/templates/pages/scaffolding.mustache new file mode 100644 index 0000000..13c777a --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/scaffolding.mustache @@ -0,0 +1,556 @@ + +
    +

    {{_i}}Scaffolding{{/i}}

    +

    {{_i}}Bootstrap is built on a responsive 12-column grid. We've also included fixed- and fluid-width layouts based on that system.{{/i}}

    + +
    + + + + + +
    + +
    +
    +

    {{_i}}Requires HTML5 doctype{{/i}}

    +

    {{_i}}Bootstrap makes use of HTML elements and CSS properties that require the use of the HTML5 doctype. Be sure to include it at the beginning of every Bootstrapped page in your project.{{/i}}

    +
    +<!DOCTYPE html>
    +<html lang="en">
    +  ...
    +</html>
    +
    +
    +
    +

    {{_i}}Typography and links{{/i}}

    +

    {{_i}}Within the scaffolding.less file, we set basic global display, typography, and link styles. Specifically, we:{{/i}}

    +
      +
    • {{_i}}Remove margin on the body{{/i}}
    • +
    • {{_i}}Set background-color: white; on the body{{/i}}
    • +
    • {{_i}}Use the @baseFontFamily, @baseFontSize, and @baseLineHeight attributes as our typographyic base{{/i}}
    • +
    • {{_i}}Set the global link color via @linkColor and apply link underlines only on :hover{{/i}}
    • +
    +
    +
    +

    {{_i}}Reset via Normalize{{/i}}

    +

    {{_i}}As of Bootstrap 2, the traditional CSS reset has evolved to make use of elements from Normalize.css, a project by Nicolas Gallagher that also powers the HTML5 Boilerplate.{{/i}}

    +

    {{_i}}The new reset can still be found in reset.less, but with many elements removed for brevity and accuracy.{{/i}}

    +
    +
    +
    + + + + + +
    + + +
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    +
    +
    4
    +
    4
    +
    4
    +
    +
    +
    4
    +
    8
    +
    +
    +
    6
    +
    6
    +
    +
    +
    12
    +
    +
    +
    +

    {{_i}}The default grid system provided as part of Bootstrap is a 940px-wide, 12-column grid.{{/i}}

    +

    {{_i}}It also has four responsive variations for various devices and resolutions: phone, tablet portrait, tablet landscape and small desktops, and large widescreen desktops.{{/i}}

    +
    +
    +
    +<div class="row">
    +  <div class="span4">...</div>
    +  <div class="span8">...</div>
    +</div>
    +
    +
    +
    +

    {{_i}}As shown here, a basic layout can be created with two "columns", each spanning a number of the 12 foundational columns we defined as part of our grid system.{{/i}}

    +
    +
    + +
    + +

    {{_i}}Offsetting columns{{/i}}

    +
    +
    4
    +
    4 offset 4
    +
    +
    +
    3 offset 3
    +
    3 offset 3
    +
    +
    +
    8 offset 4
    +
    +
    +<div class="row">
    +  <div class="span4">...</div>
    +  <div class="span4 offset4">...</div>
    +</div>
    +
    + +
    + +

    {{_i}}Nesting columns{{/i}}

    +
    +
    +

    {{_i}}With the static (non-fluid) grid system in Bootstrap, nesting is easy. To nest your content, just add a new .row and set of .span* columns within an existing .span* column.{{/i}}

    +

    {{_i}}Example{{/i}}

    +

    {{_i}}Nested rows should include a set of columns that add up to the number of columns of it's parent. For example, two nested .span3 columns should be placed within a .span6.{{/i}}

    +
    +
    + {{_i}}Level 1 of column{{/i}} +
    +
    + {{_i}}Level 2{{/i}} +
    +
    + {{_i}}Level 2{{/i}} +
    +
    +
    +
    +
    +
    +
    +<div class="row">
    +  <div class="span12">
    +    {{_i}}Level 1 of column{{/i}}
    +    <div class="row">
    +      <div class="span6">{{_i}}Level 2{{/i}}</div>
    +      <div class="span6">{{_i}}Level 2{{/i}}</div>
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    +
    + + + + +
    + + +

    {{_i}}Fluid columns{{/i}}

    +
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    1
    +
    +
    +
    4
    +
    4
    +
    4
    +
    +
    +
    4
    +
    8
    +
    +
    +
    6
    +
    6
    +
    +
    +
    12
    +
    + +
    +
    +

    {{_i}}Percents, not pixels{{/i}}

    +

    {{_i}}The fluid grid system uses percents for column widths instead of fixed pixels. It also has the same responsive variations as our fixed grid system, ensuring proper proportions for key screen resolutions and devices.{{/i}}

    +
    +
    +

    {{_i}}Fluid rows{{/i}}

    +

    {{_i}}Make any row fluid simply by changing .row to .row-fluid. The columns stay the exact same, making it super straightforward to flip between fixed and fluid layouts.{{/i}}

    +
    +
    +

    {{_i}}Markup{{/i}}

    +
    +<div class="row-fluid">
    +  <div class="span4">...</div>
    +  <div class="span8">...</div>
    +</div>
    +
    +
    +
    + +

    {{_i}}Fluid nesting{{/i}}

    +
    +
    +

    {{_i}}Nesting with fluid grids is a bit different: the number of nested columns doesn't need to match the parent. Instead, your columns are reset at each level because each row takes up 100% of the parent column.{{/i}}

    +
    +
    + {{_i}}Fluid 12{{/i}} +
    +
    + {{_i}}Fluid 6{{/i}} +
    +
    + {{_i}}Fluid 6{{/i}} +
    +
    +
    +
    +
    +
    +
    +<div class="row-fluid">
    +  <div class="span12">
    +    {{_i}}Level 1 of column{{/i}}
    +    <div class="row-fluid">
    +      <div class="span6">{{_i}}Level 2{{/i}}</div>
    +      <div class="span6">{{_i}}Level 2{{/i}}</div>
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Variable{{/i}}{{_i}}Default value{{/i}}{{_i}}Description{{/i}}
    @gridColumns12{{_i}}Number of columns{{/i}}
    @gridColumnWidth60px{{_i}}Width of each column{{/i}}
    @gridGutterWidth20px{{_i}}Negative space between columns{{/i}}
    +
    +
    +

    {{_i}}Variables in LESS{{/i}}

    +

    {{_i}}Built into Bootstrap are a handful of variables for customizing the default 940px grid system, documented above. All variables for the grid are stored in variables.less.{{/i}}

    +
    +
    +

    {{_i}}How to customize{{/i}}

    +

    {{_i}}Modifying the grid means changing the three @grid* variables and recompiling Bootstrap. Change the grid variables in variables.less and use one of the four ways documented to recompile. If you're adding more columns, be sure to add the CSS for those in grid.less.{{/i}}

    +
    +
    +

    {{_i}}Staying responsive{{/i}}

    +

    {{_i}}Customization of the grid only works at the default level, the 940px grid. To maintain the responsive aspects of Bootstrap, you'll also have to customize the grids in responsive.less.{{/i}}

    +
    +
    + +
    + + + + +
    + + +
    +
    +

    {{_i}}Fixed layout{{/i}}

    +

    {{_i}}The default and simple 940px-wide, centered layout for just about any website or page provided by a single <div class="container">.{{/i}}

    +
    +
    +
    +
    +<body>
    +  <div class="container">
    +    ...
    +  </div>
    +</body>
    +
    +
    +
    +

    {{_i}}Fluid layout{{/i}}

    +

    {{_i}}<div class="container-fluid"> gives flexible page structure, min- and max-widths, and a left-hand sidebar. It's great for apps and docs.{{/i}}

    +
    +
    +
    +
    +
    +<div class="container-fluid">
    +  <div class="row-fluid">
    +    <div class="span2">
    +      <!--{{_i}}Sidebar content{{/i}}-->
    +    </div>
    +    <div class="span10">
    +      <!--{{_i}}Body content{{/i}}-->
    +    </div>
    +  </div>
    +</div>
    +
    +
    +
    +
    + + + + + +
    + + +
    +
    +

    Responsive devices

    +

    {{_i}}What they do{{/i}}

    +

    {{_i}}Media queries allow for custom CSS based on a number of conditions—ratios, widths, display type, etc—but usually focuses around min-width and max-width.{{/i}}

    +
      +
    • {{_i}}Modify the width of column in our grid{{/i}}
    • +
    • {{_i}}Stack elements instead of float wherever necessary{{/i}}
    • +
    • {{_i}}Resize headings and text to be more appropriate for devices{{/i}}
    • +
    +

    {{_i}}Use media queries responsibly and only as a start to your mobile audiences. For larger projects, do consider dedicated code bases and not layers of media queries.{{/i}}

    +
    +
    +

    {{_i}}Supported devices{{/i}}

    +

    {{_i}}Bootstrap supports a handful of media queries in a single file to help make your projects more appropriate on different devices and screen resolutions. Here's what's included:{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Label{{/i}}{{_i}}Layout width{{/i}}{{_i}}Column width{{/i}}{{_i}}Gutter width{{/i}}
    {{_i}}Smartphones{{/i}}480px and below{{_i}}Fluid columns, no fixed widths{{/i}}
    {{_i}}Smartphones to tablets{{/i}}767px and below{{_i}}Fluid columns, no fixed widths{{/i}}
    {{_i}}Portrait tablets{{/i}}768px and above42px20px
    {{_i}}Default{{/i}}980px and up60px20px
    {{_i}}Large display{{/i}}1200px and up70px30px
    + +

    {{_i}}Requires meta tag{{/i}}

    +

    {{_i}}To ensure devices display responsive pages properly, include the viewport meta tag.{{/i}}

    +
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    +
    +
    + +
    + + +

    {{_i}}Using the media queries{{/i}}

    +
    +
    +

    {{_i}}Bootstrap doesn't automatically include these media queries, but understanding and adding them is very easy and requires minimal setup. You have a few options for including the responsive features of Bootstrap:{{/i}}

    +
      +
    1. {{_i}}Use the compiled responsive version, bootstrap-responsive.css{{/i}}
    2. +
    3. {{_i}}Add @import "responsive.less" and recompile Bootstrap{{/i}}
    4. +
    5. {{_i}}Modify and recompile responsive.less as a separate file{{/i}}
    6. +
    +

    {{_i}}Why not just include it? Truth be told, not everything needs to be responsive. Instead of encouraging developers to remove this feature, we figure it best to enable it.{{/i}}

    +
    +
    +
    +  // {{_i}}Landscape phones and down{{/i}}
    +  @media (max-width: 480px) { ... }
    +
    +  // {{_i}}Landscape phone to portrait tablet{{/i}}
    +  @media (max-width: 767px) { ... }
    +
    +  // {{_i}}Portrait tablet to landscape and desktop{{/i}}
    +  @media (min-width: 768px) and (max-width: 979px) { ... }
    +
    +  // {{_i}}Large desktop{{/i}}
    +  @media (min-width: 1200px) { ... }
    +
    +
    +
    +
    + + +

    {{_i}}Responsive utility classes{{/i}}

    +
    +
    +

    {{_i}}What are they{{/i}}

    +

    {{_i}}For faster mobile-friendly development, use these basic utility classes for showing and hiding content by device.{{/i}}

    +

    {{_i}}When to use{{/i}}

    +

    {{_i}}Use on a limited basis and avoid creating entirely different versions of the same site. Instead, use them to complement each device's presentation.{{/i}}

    +

    {{_i}}For example, you might show a <select> element for nav on mobile layouts, but not on tablets or desktops.{{/i}}

    +
    +
    +

    {{_i}}Support classes{{/i}}

    +

    {{_i}}Shown here is a table of the classes we support and their effect on a given media query layout (labeled by device). They can be found in responsive.less.{{/i}}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{_i}}Class{{/i}}{{_i}}Phones 480px and below{{/i}}{{_i}}Tablets 767px and below{{/i}}{{_i}}Desktops 768px and above{{/i}}
    .visible-phone{{_i}}Visible{{/i}}
    .visible-tablet{{_i}}Visible{{/i}}
    .visible-desktop{{_i}}Visible{{/i}}
    .hidden-phone{{_i}}Visible{{/i}}{{_i}}Visible{{/i}}
    .hidden-tablet{{_i}}Visible{{/i}}{{_i}}Visible{{/i}}
    .hidden-desktop{{_i}}Visible{{/i}}{{_i}}Visible{{/i}}
    +

    {{_i}}Test case{{/i}}

    +

    {{_i}}Resize your browser or load on different devices to test the above classes.{{/i}}

    +

    {{_i}}Visible on...{{/i}}

    +

    {{_i}}Green checkmarks indicate that class is visible in your current viewport.{{/i}}

    +
      +
    • {{_i}}Phone{{/i}}✔ {{_i}}Phone{{/i}}
    • +
    • {{_i}}Tablet{{/i}}✔ {{_i}}Tablet{{/i}}
    • +
    • {{_i}}Desktop{{/i}}✔ {{_i}}Desktop{{/i}}
    • +
    +

    {{_i}}Hidden on...{{/i}}

    +

    {{_i}}Here, green checkmarks indicate that class is hidden in your current viewport.{{/i}}

    +
      +
    • {{_i}}Phone{{/i}}✔ {{_i}}Phone{{/i}}
    • +
    • {{_i}}Tablet{{/i}}✔ {{_i}}Tablet{{/i}}
    • +
    • {{_i}}Desktop{{/i}}✔ {{_i}}Desktop{{/i}}
    • +
    +
    +
    + + +
    +
    +
    +
    +
    diff --git a/test/public/bootstrap/docs/templates/pages/upgrading.mustache b/test/public/bootstrap/docs/templates/pages/upgrading.mustache new file mode 100644 index 0000000..5a82e2d --- /dev/null +++ b/test/public/bootstrap/docs/templates/pages/upgrading.mustache @@ -0,0 +1,194 @@ + +
    +

    {{_i}}Upgrading to Bootstrap 2{{/i}}

    +

    {{_i}}Learn about significant changes and additions since v1.4 with this handy guide.{{/i}}

    +
    + + + + +
    + +
      +
    • {{_i}}Docs: major updates across the board to general structure, examples, and code snippets. Also made responsive with new media queries.{{/i}}
    • +
    • {{_i}}Docs: all docs pages are now powered by Mustache templates and strings are wrapped in i18n tags for translation by the Twitter Translation Center. All changes to documentation must be done here and then compiled (similar to our CSS and LESS).{{/i}}
    • +
    • {{_i}}Repo directory structure: removed the compiled CSS from the root in favor of a large direct download link on the docs homepage. Compiled CSS is in /docs/assets/css/.{{/i}}
    • +
    • {{_i}}Docs and repo: one makefile, just type make in the Terminal and get updated docs and CSS.{{/i}}
    • +
    +
    + + + + +
    + +

    {{_i}}Grid system{{/i}}

    +
      +
    • {{_i}}Updated grid system, now only 12 columns instead of 16{{/i}} +
    • {{_i}}Responsive approach means your projects virtually work out of the box on smartphones, tablets, and more{{/i}}
    • +
    • {{_i}}Removed unused (by default) grid columns support for 17-24 columns{{/i}}
    • +
    +

    {{_i}}Responsive (media queries){{/i}}

    +
      +
    • {{_i}}Media queries added for basic support across mobile and tablet devices{{/i}} +
    • {{_i}}Responsive CSS is compiled separately, as bootstrap-responsive.css{{/i}}
    • +
    +
    + + + + +
    + +

    {{_i}}Typography{{/i}}

    +
      +
    • {{_i}}h4 elements were dropped from 16px to 14px with a default line-height of 18px{{/i}}
    • +
    • {{_i}}h5 elements were dropped from 14px to 12px{{/i}}
    • +
    • {{_i}}h6 elements were dropped from 13px to 11px{{/i}}
    • +
    • {{_i}}Right-aligned option for blockquotes if float: right;{{/i}}
    • +
    +

    {{_i}}Code{{/i}}

    +
      +
    • {{_i}}New graphical style for <code>{{/i}}
    • +
    • {{_i}}Google Code Prettify styles updated (based on GitHub's gists){{/i}}
    • +
    +

    {{_i}}Tables{{/i}}

    +
      +
    • {{_i}}Improved support for colspan and rowspan{{/i}}
    • +
    • {{_i}}Styles now restricted to new base class, .table{{/i}}
    • +
    • {{_i}}Table classes standardized with .table- required as a prefix{{/i}}
    • +
    • {{_i}}Removed unused table color options (too much code for such little impact){{/i}}
    • +
    • {{_i}}Dropped support for TableSorter{{/i}}
    • +
    +

    {{_i}}Buttons{{/i}}

    +
      +
    • {{_i}}New classes for colors and sizes, all prefixed with .btn-{{/i}}
    • +
    • {{_i}}IE9: removed gradients and added rounded corners{{/i}}
    • +
    • {{_i}}Updated active state to make styling clearer in button groups (new) and look better with custom transition{{/i}}
    • +
    • {{_i}}New mixin, .buttonBackground, to set button gradients{{/i}}
    • +
    • {{_i}}The .secondary class was removed from modal examples in our docs as it never had associated styles.{{/i}}
    • +
    +

    {{_i}}Forms{{/i}}

    +
      +
    • {{_i}}Default form style is now vertical (stacked) to use less CSS and add greater flexibility{{/i}}
    • +
    • {{_i}}Form classes standardized with .form- required as a prefix{{/i}}
    • +
    • {{_i}}New built-in form defaults for search, inline, and horizontal forms{{/i}}
    • +
    • {{_i}}For horizontal forms, previous classes .clearfix and .input are equivalent to the new .control-group and .controls.{{/i}}
    • +
    • {{_i}}More flexible horizontal form markup with classes for all styling, including new optional class for the label{{/i}}
    • +
    • {{_i}}Form states: colors updated and customizable via new LESS variables{{/i}}
    • +
    +

    {{_i}}Icons, by Glyphicons{{/i}}

    +
      +
    • {{_i}}New Glyphicons Halflings icon set added in sprite form, in black and white{{/i}}
    • +
    • {{_i}}Simple markup required for an icon in tons of contexts: <i class="icon-cog"></>{{/i}}
    • +
    • {{_i}}Add another class, .icon-white, for white variation of the same icon{{/i}}
    • +
    +
    + + + + +
    + +

    {{_i}}Button groups and dropdowns{{/i}}

    +
      +
    • {{_i}}Two brand new components in 2.0: button groups and button dropdowns{{/i}}
    • +
    • {{_i}}Dependency: button dropdowns are built on button groups, and therefore require all their styles{{/i}}
    • +
    • {{_i}}Button groups, .btn-group, can be grouped one level higher with a button toolbar, .btn-toolbar{{/i}}
    • +
    +

    {{_i}}Navigation{{/i}}

    +
      +
    • {{_i}}Tabs and pills now require the use of a new base class, .nav, on their <ul> and the class names are now .nav-pills and .nav-tabs.{{/i}}
    • +
    • {{_i}}New nav list variation added that uses the same base class, .nav{{/i}}
    • +
    • {{_i}}Vertical tabs and pills have been added—just add .nav-stacked to the <ul>{{/i}}
    • +
    • {{_i}}Pills were restyled to be less rounded by default{{/i}}
    • +
    • {{_i}}Pills now have dropdown menu support (they share the same markup and styles as tabs){{/i}}
    • +
    +

    {{_i}}Navbar (formerly topbar){{/i}}

    +
      +
    • {{_i}}Base class changed from .topbar to .navbar{{/i}}
    • +
    • {{_i}}Now supports static position (default behavior, not fixed) and fixed to the top of viewport via .navbar-fixed-top (previously only supported fixed){{/i}}
    • +
    • {{_i}}Added vertical dividers to top-level nav{{/i}}
    • +
    • {{_i}}Improved support for inline forms in the navbar, which now require .navbar-form to properly scope styles to only the intended forms.{{/i}}
    • +
    • {{_i}}Navbar search form now requires use of the .navbar-search class and its input the use of .search-query. To position the search form, you must use .pull-left or .pull-right.{{/i}}
    • +
    • {{_i}}Added optional responsive markup for collapsing navbar contents for smaller resolutions and devices. See navbar docs for how to utilize.{{/i}}
    • +
    +

    {{_i}}Dropdown menus{{/i}}

    +
      +
    • {{_i}}Updated the .dropdown-menu to tighten up spacing{{/i}}
    • +
    • {{_i}}Now requires you to add a <span class="caret"></span> to show the dropdown arrow{{/i}}
    • +
    • {{_i}}Now requires you to add a data-toggle="dropdown" attribute to obtain toggling behavior{{/i}}
    • +
    • {{_i}}The navbar (fixed topbar) has brand new dropdowns. Gone are the dark versions and in their place are the standard white ones with an additional caret at their tops for clarity of position.{{/i}}
    • +
    +

    {{_i}}Labels{{/i}}

    +
      +
    • {{_i}}Label colors updated to match form state colors{{/i}}
    • +
    • {{_i}}Not only do they match graphically, but they are powered by the same new variables{{/i}}
    • +
    +

    {{_i}}Thumbnails{{/i}}

    +
      +
    • {{_i}}Formerly .media-grid, now just .thumbnails, we've thoroughly extended this component for more uses while maintaining overall simplicity out of the box.{{/i}}
    • +
    • {{_i}}Individual thumbnails now require .thumbnail class{{/i}}
    • +
    +

    {{_i}}Alerts{{/i}}

    +
      +
    • {{_i}}New base class: .alert instead of .alert-message{{/i}}
    • +
    • {{_i}}Class names standardized for other options, now all starting with .alert-{{/i}}
    • +
    • {{_i}}Redesigned base alert styles to combine the default alerts and block-level alerts into one{{/i}}
    • +
    • {{_i}}Block level alert class changed: .alert-block instead of .block-message{{/i}}
    • +
    +

    {{_i}}Progress bars{{/i}}

    +
      +
    • {{_i}}New in 2.0{{/i}}
    • +
    • {{_i}}Features multiple styles via classes, including striped and animated variations via CSS3{{/i}}
    • +
    +

    {{_i}}Miscellaneous components{{/i}}

    +
      +
    • {{_i}}Added documentation for the well component and the close icon (used in modals and alerts){{/i}}
    • +
    +
    + + + + +
    + +
    + {{_i}}Heads up!{{/i}} {{_i}}We've rewritten just about everything for our plugins, so head on over to the Javascript page to learn more.{{/i}} +
    +

    {{_i}}Tooltips{{/i}}

    +
      +
    • {{_i}}The plugin method has been renamed from twipsy() to tooltip(), and the class name changed from twipsy to tooltip.{{/i}}
    • +
    • {{_i}}The placement option value that was below is now bottom, and above is now top.{{/i}}
    • +
    • {{_i}}The animate option was renamed to animation.{{/i}}
    • +
    • {{_i}}The html option was removed, as the tooltips default to allowing HTML now.{{/i}}
    • +
    +

    {{_i}}Popovers{{/i}}

    +
      +
    • {{_i}}Child elements now properly namespaced: .title to .popover-title, .inner to .popover-inner, and .content to .popover-content.{{/i}}
    • +
    • {{_i}}The placement option value that was below is now bottom, and above is now top.{{/i}}
    • +
    +

    {{_i}}New plugins{{/i}}

    + +
    + diff --git a/test/public/bootstrap/docs/upgrading.html b/test/public/bootstrap/docs/upgrading.html new file mode 100644 index 0000000..2a27b00 --- /dev/null +++ b/test/public/bootstrap/docs/upgrading.html @@ -0,0 +1,309 @@ + + + + + Upgrading · Twitter Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    +

    Upgrading to Bootstrap 2

    +

    Learn about significant changes and additions since v1.4 with this handy guide.

    +
    + + + + +
    + +
      +
    • Docs: major updates across the board to general structure, examples, and code snippets. Also made responsive with new media queries.
    • +
    • Docs: all docs pages are now powered by Mustache templates and strings are wrapped in i18n tags for translation by the Twitter Translation Center. All changes to documentation must be done here and then compiled (similar to our CSS and LESS).
    • +
    • Repo directory structure: removed the compiled CSS from the root in favor of a large direct download link on the docs homepage. Compiled CSS is in /docs/assets/css/.
    • +
    • Docs and repo: one makefile, just type make in the Terminal and get updated docs and CSS.
    • +
    +
    + + + + +
    + +

    Grid system

    +
      +
    • Updated grid system, now only 12 columns instead of 16 +
    • Responsive approach means your projects virtually work out of the box on smartphones, tablets, and more
    • +
    • Removed unused (by default) grid columns support for 17-24 columns
    • +
    +

    Responsive (media queries)

    +
      +
    • Media queries added for basic support across mobile and tablet devices +
    • Responsive CSS is compiled separately, as bootstrap-responsive.css
    • +
    +
    + + + + +
    + +

    Typography

    +
      +
    • h4 elements were dropped from 16px to 14px with a default line-height of 18px
    • +
    • h5 elements were dropped from 14px to 12px
    • +
    • h6 elements were dropped from 13px to 11px
    • +
    • Right-aligned option for blockquotes if float: right;
    • +
    +

    Code

    +
      +
    • New graphical style for <code>
    • +
    • Google Code Prettify styles updated (based on GitHub's gists)
    • +
    +

    Tables

    +
      +
    • Improved support for colspan and rowspan
    • +
    • Styles now restricted to new base class, .table
    • +
    • Table classes standardized with .table- required as a prefix
    • +
    • Removed unused table color options (too much code for such little impact)
    • +
    • Dropped support for TableSorter
    • +
    +

    Buttons

    +
      +
    • New classes for colors and sizes, all prefixed with .btn-
    • +
    • IE9: removed gradients and added rounded corners
    • +
    • Updated active state to make styling clearer in button groups (new) and look better with custom transition
    • +
    • New mixin, .buttonBackground, to set button gradients
    • +
    • The .secondary class was removed from modal examples in our docs as it never had associated styles.
    • +
    +

    Forms

    +
      +
    • Default form style is now vertical (stacked) to use less CSS and add greater flexibility
    • +
    • Form classes standardized with .form- required as a prefix
    • +
    • New built-in form defaults for search, inline, and horizontal forms
    • +
    • For horizontal forms, previous classes .clearfix and .input are equivalent to the new .control-group and .controls.
    • +
    • More flexible horizontal form markup with classes for all styling, including new optional class for the label
    • +
    • Form states: colors updated and customizable via new LESS variables
    • +
    +

    Icons, by Glyphicons

    +
      +
    • New Glyphicons Halflings icon set added in sprite form, in black and white
    • +
    • Simple markup required for an icon in tons of contexts: <i class="icon-cog"></>
    • +
    • Add another class, .icon-white, for white variation of the same icon
    • +
    +
    + + + + +
    + +

    Button groups and dropdowns

    +
      +
    • Two brand new components in 2.0: button groups and button dropdowns
    • +
    • Dependency: button dropdowns are built on button groups, and therefore require all their styles
    • +
    • Button groups, .btn-group, can be grouped one level higher with a button toolbar, .btn-toolbar
    • +
    +

    Navigation

    +
      +
    • Tabs and pills now require the use of a new base class, .nav, on their <ul> and the class names are now .nav-pills and .nav-tabs.
    • +
    • New nav list variation added that uses the same base class, .nav
    • +
    • Vertical tabs and pills have been added—just add .nav-stacked to the <ul>
    • +
    • Pills were restyled to be less rounded by default
    • +
    • Pills now have dropdown menu support (they share the same markup and styles as tabs)
    • +
    +

    Navbar (formerly topbar)

    +
      +
    • Base class changed from .topbar to .navbar
    • +
    • Now supports static position (default behavior, not fixed) and fixed to the top of viewport via .navbar-fixed-top (previously only supported fixed)
    • +
    • Added vertical dividers to top-level nav
    • +
    • Improved support for inline forms in the navbar, which now require .navbar-form to properly scope styles to only the intended forms.
    • +
    • Navbar search form now requires use of the .navbar-search class and its input the use of .search-query. To position the search form, you must use .pull-left or .pull-right.
    • +
    • Added optional responsive markup for collapsing navbar contents for smaller resolutions and devices. See navbar docs for how to utilize.
    • +
    +

    Dropdown menus

    +
      +
    • Updated the .dropdown-menu to tighten up spacing
    • +
    • Now requires you to add a <span class="caret"></span> to show the dropdown arrow
    • +
    • Now requires you to add a data-toggle="dropdown" attribute to obtain toggling behavior
    • +
    • The navbar (fixed topbar) has brand new dropdowns. Gone are the dark versions and in their place are the standard white ones with an additional caret at their tops for clarity of position.
    • +
    +

    Labels

    +
      +
    • Label colors updated to match form state colors
    • +
    • Not only do they match graphically, but they are powered by the same new variables
    • +
    +

    Thumbnails

    +
      +
    • Formerly .media-grid, now just .thumbnails, we've thoroughly extended this component for more uses while maintaining overall simplicity out of the box.
    • +
    • Individual thumbnails now require .thumbnail class
    • +
    +

    Alerts

    +
      +
    • New base class: .alert instead of .alert-message
    • +
    • Class names standardized for other options, now all starting with .alert-
    • +
    • Redesigned base alert styles to combine the default alerts and block-level alerts into one
    • +
    • Block level alert class changed: .alert-block instead of .block-message
    • +
    +

    Progress bars

    +
      +
    • New in 2.0
    • +
    • Features multiple styles via classes, including striped and animated variations via CSS3
    • +
    +

    Miscellaneous components

    +
      +
    • Added documentation for the well component and the close icon (used in modals and alerts)
    • +
    +
    + + + + +
    + +
    + Heads up! We've rewritten just about everything for our plugins, so head on over to the Javascript page to learn more. +
    +

    Tooltips

    +
      +
    • The plugin method has been renamed from twipsy() to tooltip(), and the class name changed from twipsy to tooltip.
    • +
    • The placement option value that was below is now bottom, and above is now top.
    • +
    • The animate option was renamed to animation.
    • +
    • The html option was removed, as the tooltips default to allowing HTML now.
    • +
    +

    Popovers

    +
      +
    • Child elements now properly namespaced: .title to .popover-title, .inner to .popover-inner, and .content to .popover-content.
    • +
    • The placement option value that was below is now bottom, and above is now top.
    • +
    +

    New plugins

    + +
    + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/public/bootstrap/img/glyphicons-halflings-white.png b/test/public/bootstrap/img/glyphicons-halflings-white.png new file mode 100644 index 0000000..3bf6484 Binary files /dev/null and b/test/public/bootstrap/img/glyphicons-halflings-white.png differ diff --git a/test/public/bootstrap/img/glyphicons-halflings.png b/test/public/bootstrap/img/glyphicons-halflings.png new file mode 100644 index 0000000..79bc568 Binary files /dev/null and b/test/public/bootstrap/img/glyphicons-halflings.png differ diff --git a/test/public/bootstrap/js/.jshintrc b/test/public/bootstrap/js/.jshintrc new file mode 100644 index 0000000..bbac349 --- /dev/null +++ b/test/public/bootstrap/js/.jshintrc @@ -0,0 +1,10 @@ +{ + "validthis": true, + "laxcomma" : true, + "laxbreak" : true, + "browser" : true, + "debug" : true, + "boss" : true, + "expr" : true, + "asi" : true +} \ No newline at end of file diff --git a/test/public/bootstrap/js/README.md b/test/public/bootstrap/js/README.md new file mode 100644 index 0000000..c7b71e7 --- /dev/null +++ b/test/public/bootstrap/js/README.md @@ -0,0 +1,112 @@ +## 2.0 BOOTSTRAP JS PHILOSOPHY +These are the high-level design rules which guide the development of Bootstrap's plugin apis. + +--- + +### DATA-ATTRIBUTE API + +We believe you should be able to use all plugins provided by Bootstrap purely through the markup API without writing a single line of javascript. This is bootstraps first class api. + +We acknowledge that this isn't always the most performant and sometimes it may be desirable to turn this functionality off altogether. Therefore, as of 2.0 we provide the ability to disable the data attribute API by unbinding all events on the body namespaced with `'data-api'`. This looks like this: + + $('body').off('.data-api') + +To target a specific plugin, just include the plugins name as a namespace along with the data-api namespace like this: + + $('body').off('.alert.data-api') + +--- + +### PROGRAMATIC API + +We also believe you should be able to use all plugins provided by Bootstrap purely through the JS API. + +All public APIs should be single, chainable methods, and return the collection acted upon. + + $(".btn.danger").button("toggle").addClass("fat") + +All methods should accept an optional options object, a string which targets a particular method, or null which initiates the default behavior: + + $("#myModal").modal() // initialized with defaults + $("#myModal").modal({ keyboard: false }) // initialized with no keyboard + $("#myModal").modal('show') // initializes and invokes show immediately + +--- + +### OPTIONS + +Options should be sparse and add universal value. We should pick the right defaults. + +All plugins should have a default object which can be modified to affect all instances' default options. The defaults object should be available via `$.fn.plugin.defaults`. + + $.fn.modal.defaults = { … } + +An options definition should take the following form: + + *noun*: *adjective* - describes or modifies a quality of an instance + +examples: + + backdrop: true + keyboard: false + placement: 'top' + +--- + +### EVENTS + +All events should have an infinitive and past participle form. The infinitive is fired just before an action takes place, the past participle on completion of the action. + + show | shown + hide | hidden + +All infinitive events should provide preventDefault functionality. This provides the abililty to stop the execution of an action. + + $('#myModal').on('show', function (e) { + if (!data) return e.preventDefault() // stops modal from being shown + }) + +--- + +### CONSTRUCTORS + +Each plugin should expose its raw constructor on a `Constructor` property -- accessed in the following way: + + + $.fn.popover.Constructor + +--- + +### DATA ACCESSOR + +Each plugin stores a copy of the invoked class on an object. This class instance can be accessed directly through jQuery's data API like this: + + $('[rel=popover]').data('popover') instanceof $.fn.popover.Constructor + +--- + +### DATA ATTRIBUTES + +Data attributes should take the following form: + +- data-{{verb}}={{plugin}} - defines main interaction +- data-target || href^=# - defined on "control" element (if element controls an element other than self) +- data-{{noun}} - defines class instance options + +examples: + + // control other targets + data-toggle="modal" data-target="#foo" + data-toggle="collapse" data-target="#foo" data-parent="#bar" + + // defined on element they control + data-spy="scroll" + + data-dismiss="modal" + data-dismiss="alert" + + data-toggle="dropdown" + + data-toggle="button" + data-toggle="buttons-checkbox" + data-toggle="buttons-radio" \ No newline at end of file diff --git a/test/public/bootstrap/js/bootstrap-alert.js b/test/public/bootstrap/js/bootstrap-alert.js new file mode 100644 index 0000000..fa0806e --- /dev/null +++ b/test/public/bootstrap/js/bootstrap-alert.js @@ -0,0 +1,90 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/test/public/bootstrap/js/bootstrap-button.js b/test/public/bootstrap/js/bootstrap-button.js new file mode 100644 index 0000000..a9e6ba7 --- /dev/null +++ b/test/public/bootstrap/js/bootstrap-button.js @@ -0,0 +1,96 @@ +/* ============================================================ + * bootstrap-button.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON DATA-API + * =============== */ + + $(function () { + $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/test/public/bootstrap/js/bootstrap-carousel.js b/test/public/bootstrap/js/bootstrap-carousel.js new file mode 100644 index 0000000..96e5a81 --- /dev/null +++ b/test/public/bootstrap/js/bootstrap-carousel.js @@ -0,0 +1,169 @@ +/* ========================================================== + * bootstrap-carousel.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.options = options + this.options.slide && this.slide(this.options.slide) + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , to: function (pos) { + var $active = this.$element.find('.active') + , children = $active.parent().children() + , activePos = children.index($active) + , that = this + + if (pos > (children.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activePos == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e = $.Event('slide') + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + if ($next.hasClass('active')) return + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (typeof option == 'string' || (option = options.slide)) data[option]() + else if (options.interval) data.cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL DATA-API + * ================= */ + + $(function () { + $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() + }) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/test/public/bootstrap/js/bootstrap-collapse.js b/test/public/bootstrap/js/bootstrap-collapse.js new file mode 100644 index 0000000..d02f6fd --- /dev/null +++ b/test/public/bootstrap/js/bootstrap-collapse.js @@ -0,0 +1,157 @@ +/* ============================================================= + * bootstrap-collapse.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSIBLE PLUGIN DEFINITION + * ============================== */ + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = typeof option == 'object' && option + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSIBLE DATA-API + * ==================== */ + + $(function () { + $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $(target).collapse(option) + }) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/test/public/bootstrap/js/bootstrap-dropdown.js b/test/public/bootstrap/js/bootstrap-dropdown.js new file mode 100644 index 0000000..ec0588d --- /dev/null +++ b/test/public/bootstrap/js/bootstrap-dropdown.js @@ -0,0 +1,100 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle="dropdown"]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , selector + , isActive + + if ($this.is('.disabled, :disabled')) return + + selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + $parent.length || ($parent = $this.parent()) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) $parent.toggleClass('open') + + return false + } + + } + + function clearMenus() { + $(toggle).parent().removeClass('open') + } + + + /* DROPDOWN PLUGIN DEFINITION + * ========================== */ + + $.fn.dropdown = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('dropdown') + if (!data) $this.data('dropdown', (data = new Dropdown(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.dropdown.Constructor = Dropdown + + + /* APPLY TO STANDARD DROPDOWN ELEMENTS + * =================================== */ + + $(function () { + $('html').on('click.dropdown.data-api', clearMenus) + $('body') + .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/test/public/bootstrap/js/bootstrap-modal.js b/test/public/bootstrap/js/bootstrap-modal.js new file mode 100644 index 0000000..c831de6 --- /dev/null +++ b/test/public/bootstrap/js/bootstrap-modal.js @@ -0,0 +1,218 @@ +/* ========================================================= + * bootstrap-modal.js v2.0.3 + * http://twitter.github.com/bootstrap/javascript.html#modals + * ========================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================= */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* MODAL CLASS DEFINITION + * ====================== */ + + var Modal = function (content, options) { + this.options = options + this.$element = $(content) + .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) + } + + Modal.prototype = { + + constructor: Modal + + , toggle: function () { + return this[!this.isShown ? 'show' : 'hide']() + } + + , show: function () { + var that = this + , e = $.Event('show') + + this.$element.trigger(e) + + if (this.isShown || e.isDefaultPrevented()) return + + $('body').addClass('modal-open') + + this.isShown = true + + escape.call(this) + backdrop.call(this, function () { + var transition = $.support.transition && that.$element.hasClass('fade') + + if (!that.$element.parent().length) { + that.$element.appendTo(document.body) //don't move modals dom position + } + + that.$element + .show() + + if (transition) { + that.$element[0].offsetWidth // force reflow + } + + that.$element.addClass('in') + + transition ? + that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : + that.$element.trigger('shown') + + }) + } + + , hide: function (e) { + e && e.preventDefault() + + var that = this + + e = $.Event('hide') + + this.$element.trigger(e) + + if (!this.isShown || e.isDefaultPrevented()) return + + this.isShown = false + + $('body').removeClass('modal-open') + + escape.call(this) + + this.$element.removeClass('in') + + $.support.transition && this.$element.hasClass('fade') ? + hideWithTransition.call(this) : + hideModal.call(this) + } + + } + + + /* MODAL PRIVATE METHODS + * ===================== */ + + function hideWithTransition() { + var that = this + , timeout = setTimeout(function () { + that.$element.off($.support.transition.end) + hideModal.call(that) + }, 500) + + this.$element.one($.support.transition.end, function () { + clearTimeout(timeout) + hideModal.call(that) + }) + } + + function hideModal(that) { + this.$element + .hide() + .trigger('hidden') + + backdrop.call(this) + } + + function backdrop(callback) { + var that = this + , animate = this.$element.hasClass('fade') ? 'fade' : '' + + if (this.isShown && this.options.backdrop) { + var doAnimate = $.support.transition && animate + + this.$backdrop = $('