├── .gitignore
├── Procfile
├── README.md
├── app.json
├── app.py
├── db.cfg
├── requirements.txt
├── static
├── css
│ └── style.css
├── js
│ ├── general.js
│ ├── marked.min.js
│ └── vue.js
├── sfc
│ ├── .babelrc
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ │ ├── App.vue
│ │ └── main.js
│ └── webpack.config.js
└── ts
│ ├── .babelrc
│ ├── .gitignore
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── main.ts
│ └── vue-shims.d.ts
│ ├── tsconfig.json
│ └── webpack.config.js
└── templates
├── example.html
├── index.html
├── layout.html
├── more.html
├── router.html
├── sfc.html
├── sqlalchemy.html
├── typescript.html
├── vue.js_v0.10.3.html
└── vuex.html
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.db
3 | node_modules
4 |
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn app:app --log-file=-
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flask-Vue.js
2 |
3 | 🍣 compatible Vue.js v2 🍣
4 |
5 | confrict a Jinja2 delimiter and Vue.js delimiter...
6 |
7 | => change Jinja2 delimiter
8 |
9 | ```python
10 | from flask import Flask
11 |
12 | class CustomFlask(Flask):
13 | jinja_options = Flask.jinja_options.copy()
14 | jinja_options.update(dict(
15 | block_start_string='(%',
16 | block_end_string='%)',
17 | variable_start_string='((',
18 | variable_end_string='))',
19 | comment_start_string='(#',
20 | comment_end_string='#)',
21 | ))
22 |
23 | app = CustomFlask(__name__)
24 |
25 | #
26 | # your flask code here
27 | #
28 | ```
29 |
30 | - [different delimiters in jinja2 + flask](https://gist.github.com/lost-theory/3925738 "different delimiters in jinja2 + flask")
31 |
32 | => change Vue.js delimiter
33 |
34 | ```javascript
35 | var app = new Vue({
36 | el: "#app",
37 | delimiters: ["[[", "]]"],
38 | data: {
39 | message: "Hello Vue!"
40 | }
41 | })
42 | ```
43 |
44 | - [Vue.js api/#delimiters](https://vuejs.org/v2/api/#delimiters "Vue.js api/#delimiters")
45 |
46 | # Example & Tips
47 |
48 | This repository contain some example, if you want to try it please do as follows.
49 |
50 | requirements: Flask (=> pip install Flask)
51 |
52 | ```
53 | $ git clone https://github.com/yymm/flask-vuejs.git
54 | $ cd flask-vuejs
55 | $ python app.py
56 | ```
57 |
58 | see localhost:5000.
59 |
60 | ## Heroku Button
61 |
62 | Try it now.
63 |
64 | [](https://heroku.com/deploy)
65 |
66 | ## Menu
67 |
68 | - [x] Jinja2 & Vue.js
69 | - [x] with SQLAlchemy(Flask-SQLAlchemy)
70 | - [x] more...
71 | - SPA
72 | - using CDN
73 | - [x] vue-router
74 | - using Node.js(using vue-cli 'webpack-simple')
75 | - [x] Single File Component
76 | - [ ] TypeScript with Single File Component
77 | - [x] Vuex
78 | - [x] Vue.js v0.10.3
79 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flask-vue.js",
3 | "description": "Example & Tips, Flask with Vue.js. ",
4 | "image": "heroku/python",
5 | "repository": "https://github.com/yymm/flask-vuejs",
6 | "keywords": ["python", "flask", "vue.js" ]
7 | }
8 |
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template, jsonify, request
2 | from flask_sqlalchemy import SQLAlchemy
3 | from datetime import datetime
4 |
5 |
6 | class CustomFlask(Flask):
7 | jinja_options = Flask.jinja_options.copy()
8 | jinja_options.update(dict(
9 | block_start_string='{%',
10 | block_end_string='%}',
11 | variable_start_string='((',
12 | variable_end_string='))',
13 | comment_start_string='{#',
14 | comment_end_string='#}',
15 | ))
16 |
17 |
18 | app = CustomFlask(__name__)
19 | app.config.from_pyfile('db.cfg')
20 | db = SQLAlchemy(app)
21 |
22 |
23 | class Todo(db.Model):
24 | __tablename__ = 'todos'
25 | id = db.Column('todo_id', db.Integer, primary_key=True)
26 | title = db.Column(db.String(60))
27 | done = db.Column(db.Boolean)
28 | pub_date = db.Column(db.DateTime)
29 |
30 | def __init__(self, title):
31 | self.title = title
32 | self.done = False
33 | self.pub_date = datetime.utcnow()
34 |
35 | def get_dict(self):
36 | return {
37 | 'id': self.id,
38 | 'title': self.title,
39 | 'done': self.done,
40 | 'pub_date': self.pub_date.strftime('%Y-%m-%d %H:%M'),
41 | }
42 |
43 | @app.route('/')
44 | def index():
45 | return render_template('index.html')
46 |
47 |
48 | @app.route('/example')
49 | def example():
50 | message = "Hello Flask!"
51 | return render_template('example.html', message=message)
52 |
53 |
54 | @app.route('/more')
55 | def more():
56 | return render_template('more.html')
57 |
58 |
59 | def initialize_database():
60 | app.logger.info('Database is not created, exec create_all() here.')
61 | db.create_all()
62 | data1 = Todo('todo1')
63 | data2 = Todo('todo2')
64 | db.session.add(data1)
65 | db.session.add(data2)
66 | db.session.commit()
67 |
68 |
69 | @app.route('/sqlalchemy')
70 | def sqlalchemy():
71 | todos = []
72 | try:
73 | todos = Todo.query.order_by(Todo.pub_date.desc()).all()
74 | except:
75 | initialize_database()
76 | return render_template('sqlalchemy.html', todos=todos)
77 |
78 |
79 | @app.route('/sqlalchemy/get', methods=['GET'])
80 | def sqlalchemy_get():
81 | todos = Todo.query.order_by(Todo.pub_date.desc()).all()
82 | return jsonify(todos=[todo.get_dict() for todo in todos])
83 |
84 |
85 | @app.route('/sqlalchemy/new', methods=['POST'])
86 | def sqlalchemy_new():
87 | if request.json:
88 | db.session.add(Todo(request.json['title']))
89 | db.session.commit()
90 | return jsonify(status='ok') # Oops: always ok...
91 |
92 |
93 | @app.route('/sqlalchemy/update', methods=['POST'])
94 | def sqlalchemy_update():
95 | if request.json:
96 | todo = Todo.query.get(request.json['id'])
97 | todo.done = request.json['done']
98 | todo.title = request.json['title']
99 | db.session.commit()
100 | return jsonify(status='ok') # Oops: always ok...
101 |
102 |
103 | @app.route('/router')
104 | def router():
105 | return render_template('router.html')
106 |
107 |
108 | @app.route('/sfc')
109 | def sfc():
110 | return render_template('sfc.html')
111 |
112 |
113 | @app.route('/typescript')
114 | def typescript():
115 | return render_template('typescript.html')
116 |
117 |
118 | @app.route('/vuex')
119 | def vuex():
120 | return render_template('vuex.html')
121 |
122 |
123 | @app.route('/v0.10.3')
124 | def v0_10_3():
125 | return render_template('vue.js_v0.10.3.html')
126 |
127 |
128 | if __name__ == '__main__':
129 | app.run(debug=True)
130 |
--------------------------------------------------------------------------------
/db.cfg:
--------------------------------------------------------------------------------
1 | SQLALCHEMY_DATABASE_URI = 'sqlite:///test.db'
2 | SQLALCHEMY_TRACK_MODIFICATIONS = False
3 | SECRET_KEY = '\xfb\x12\xdf\xa1@i\xd6>V\xc0\xbb\x8fp\x16#Z\x0b\x81\xeb\x16'
4 | DEBUG = True
5 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask
2 | Flask-SQLAlchemy
3 | gunicorn
4 |
--------------------------------------------------------------------------------
/static/css/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | font-family: 'Helvetica Neue', Arial, sans-serif;
3 | text-align: center;
4 | padding: 0;
5 | margin: 0;
6 | }
7 |
8 | *, *:before, *:after {
9 | -moz-box-sizing: border-box;
10 | -webkit-box-sizing: border-box;
11 | box-sizing: border-box;
12 | }
13 |
14 | .box {
15 | width: 100%;
16 | height: 300px;
17 | border-top: 1px solid #222;
18 | /*padding-top: 20px;*/
19 | }
20 |
21 | #editor {
22 | margin: 0;
23 | height: inherit;
24 | font-family: 'Helvetica Neue', Arial, sans-serif;
25 | color: #333;
26 | text-align: left;
27 | }
28 |
29 | textarea, #editor div {
30 | display: inline-block;
31 | width: 49%;
32 | height: inherit;
33 | vertical-align: top;
34 | -webkit-box-sizing: border-box;
35 | -moz-box-sizing: border-box;
36 | box-sizing: border-box;
37 | padding: 0 20px;
38 | }
39 |
40 | #editor div {
41 | background-color: white;
42 | }
43 |
44 | textarea {
45 | border: none;
46 | border-right: 1px solid #ccc;
47 | resize: none;
48 | outline: none;
49 | background-color: #f6f6f6;
50 | font-size: 14px;
51 | font-family: 'Monaco', courier, monospace;
52 | padding: 20px;
53 | }
54 |
55 | code {
56 | color: #f66;
57 | }
58 |
59 | polygon {
60 | fill: #42b983;
61 | opacity: 0.75;
62 | }
63 | circle {
64 | fill: transparent;
65 | stroke: #999;
66 | }
67 |
68 | .div-column {
69 | margin: 0 30px;
70 | display: inline-block;
71 | }
72 |
73 | /* CSS Trick */
74 | #slider {
75 | max-width: 600px;
76 | text-align: center;
77 | margin: 0 auto;
78 | }
79 | #overflow {
80 | width: 100%;
81 | overflow: hidden;
82 | }
83 | #slides .inner {
84 | width: 400%;
85 | }
86 | #slides .inner {
87 | -moz-transform: translateZ(0);
88 | transform: translateZ(0);
89 | -moz-transition: all 800ms cubic-bezier(0.770, 0.000, 0.175, 1.000);
90 | transition: all 800ms cubic-bezier(0.770, 0.000, 0.175, 1.000);
91 | -moz-transition-timing-function: cubic-bezier(0.770, 0.000, 0.175, 1.000);
92 | transition-timing-function: cubic-bezier(0.770, 0.000, 0.175, 1.000);
93 | }
94 | #slides article {
95 | width: 25%;
96 | float: left;
97 | }
98 | #slide1:checked ~ #slides .inner {
99 | margin-left: 0;
100 | }
101 | #slide2:checked ~ #slides .inner {
102 | margin-left: -100%;
103 | }
104 | #slide3:checked ~ #slides .inner {
105 | margin-left: -200%;
106 | }
107 | #slide4:checked ~ #slides .inner {
108 | margin-left: -300%;
109 | }
110 | input[type="radio"] {
111 | display: none;
112 | }
113 |
114 | label {
115 | background: #CCC;
116 | display: inline-block;
117 | cursor: pointer;
118 | width: 10px;
119 | height: 10px;
120 | border-radius: 5px;
121 | }
122 |
123 | #slide1:checked ~ label[for="slide1"],
124 | #slide2:checked ~ label[for="slide2"],
125 | #slide3:checked ~ label[for="slide3"],
126 | #slide4:checked ~ label[for="slide4"] {
127 | background: #333;
128 | }
129 |
--------------------------------------------------------------------------------
/static/js/general.js:
--------------------------------------------------------------------------------
1 | Vue.config({
2 | delimiters: ['[', ']']
3 | })
4 |
5 | var simple = new Vue({
6 | el: "#simple",
7 | data: {
8 | message: 'bokete'
9 | }
10 | })
11 |
12 | var editor = new Vue({
13 | el: '#editor',
14 | data: {
15 | input: '# hello'
16 | },
17 | filters: {
18 | marked: marked
19 | }
20 | })
21 |
22 | var apiUrl = 'https://api.github.com/repos/yymm/Yoichi/commits?per_page=3&sha='
23 | var commits = new Vue({
24 | el: "#commits",
25 | data: {
26 | branch: "master"
27 | },
28 | created: function(){
29 | this.$watch('branch', function() {
30 | this.fetchData();
31 | })
32 | },
33 | filters: {
34 | truncate: function(value){
35 | var newline = value.indexOf('\n');
36 | return newline > -1 ? value.slice(0, newline) : value;
37 | },
38 | formatDate: function(value){
39 | return value.replace(/T|Z/g, ' ');
40 | }
41 | },
42 | methods: {
43 | fetchData: function(){
44 | // self = thisは肝。
45 | // onload内のcommitsをVueオブジェクト内の参照にするために必須。
46 | // thisを使うとonload実行時のthis(=多分windowオブジェクト)になってしまう。
47 | var xhr = new XMLHttpRequest(), self = this;
48 | xhr.open('GET', apiUrl + self.branch);
49 | xhr.onload = function(){
50 | self.commits = JSON.parse(xhr.responseText);
51 | }
52 | xhr.send();
53 | }
54 | }
55 | })
56 |
57 | var emailRE = emailRE = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
58 |
59 | var adduser = new Vue({
60 | el: "#adduser",
61 | data: {
62 | users: [],
63 | newUser: {
64 | name: '',
65 | email: ''
66 | },
67 | validation: {
68 | name: false,
69 | email: false
70 | }
71 | },
72 | filters: {
73 | nameValidator: function(val){
74 | this.validation.name = !!val;
75 | return val;
76 | },
77 | emailValidator: function(val){
78 | this.validation.email = emailRE.test(val);
79 | return val;
80 | }
81 | },
82 | methods: {
83 | addUser: function(e){
84 | e.preventDefault();
85 | if(this.validation.name && this.validation.email){
86 | var user = this.newUser;
87 | this.users.push(user);
88 | this.newUser = {};
89 | }
90 | }
91 | }
92 | })
93 |
94 | var data = [
95 | { name: 'Chuck Norris', power: Infinity },
96 | { name: 'Goku', power: 20000 },
97 | { name: 'Vegeta', power: 18000 },
98 | { name: 'Freeza', power: 530000 }
99 | ]
100 |
101 | Vue.component('grid', {
102 | template: "#grid-template",
103 | replace: true,
104 | created: function(){
105 | this.ascending = {};
106 | },
107 | methods: {
108 | sortBy: function(key){
109 | var asc = this.ascending[key] = !this.ascending[key];
110 | this.data.sort(function(a, b){
111 | var res = a[key] > b[key];
112 | if (asc) res = !res;
113 | return res ? 1 : -1;
114 | });
115 | }
116 | }
117 | })
118 |
119 | var gridcomponent = new Vue({
120 | el: "#grid-component",
121 | data: {
122 | gridOptions: {
123 | data: data,
124 | columns: [
125 | { header: 'Name', key: 'name' },
126 | { header: 'Power', key: 'power' }
127 | ]
128 | }
129 | }
130 | })
131 |
132 | var stats = [
133 | { label: 'A', value: 100 },
134 | { label: 'B', value: 100 },
135 | { label: 'C', value: 100 },
136 | { label: 'D', value: 100 },
137 | { label: 'E', value: 100 },
138 | { label: 'F', value: 100 }
139 | ]
140 |
141 | Vue.component('polygraph', {
142 | template: '#polygraph-template',
143 | replace: true,
144 | computed: {
145 | points: function(){
146 | var total = this.stats.length;
147 | return this.stats.map(function(stat, i){
148 | var point = valueToPoint(stat.value, i, total);
149 | return point.x + ',' + point.y;
150 | }).join(' ')
151 | }
152 | },
153 | components: {
154 | 'axis-label': {
155 | computed: {
156 | point: function(){
157 | return valueToPoint(+this.value + 10, this.$index, this.$parent.stats.length);
158 | },
159 | x: function(){
160 | return this.point.x;
161 | },
162 | y: function(){
163 | return this.point.y;
164 | }
165 | }
166 | }
167 | }
168 | })
169 |
170 | function valueToPoint(value, index, total){
171 | var x = 0,
172 | y = -value * 0.8,
173 | angle = Math.PI * 2 / total * index,
174 | cos = Math.cos(angle),
175 | sin = Math.sin(angle),
176 | tx = x * cos - y * sin + 100,
177 | ty = x * sin + y * cos + 100;
178 | return {
179 | x: tx,
180 | y: ty
181 | }
182 | }
183 |
184 |
185 | var svgsample = new Vue({
186 | el: '#svg-sample',
187 | data: {
188 | newLabel: '',
189 | stats: stats
190 | },
191 | filters: {
192 | format: function(stats){
193 | return JSON.stringify(stats, null, 2);
194 | }
195 | },
196 | methods: {
197 | add: function(){
198 | if(!this.newLabel) return;
199 | this.stats.push({
200 | label: this.newLabel,
201 | value: 100
202 | });
203 | this.newLabel = '';
204 | },
205 | remove: function(stat){
206 | if(this.stats.length > 3){
207 | this.stats.remove(stat.$data);
208 | }
209 | }
210 | }
211 | })
212 |
213 |
214 | Vue.component('img-slider', {
215 | template: '#img-slider-template',
216 | replace: true
217 | })
218 |
219 | new Vue({el: '#image-slider'})
220 |
--------------------------------------------------------------------------------
/static/js/marked.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/chjj/marked
5 | */
6 | (function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr",/\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if(top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.url.exec(src)){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);out+=this.outputLink(cap,{href:cap[2],title:cap[3]});continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}out+=this.outputLink(cap,link);continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/--/g,"—").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+=""+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return""+(escaped?code:escape(code,true))+"\n
"}return''+(escaped?code:escape(code,true))+"\n
\n"};Renderer.prototype.blockquote=function(quote){return"\n"+quote+"
\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"\n"};Renderer.prototype.hr=function(){return"
\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+""+type+">\n"};Renderer.prototype.listitem=function(text){return""+text+"\n"};Renderer.prototype.paragraph=function(text){return""+text+"
\n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
\n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"
\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+""+type+">\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+"
"};Renderer.prototype.br=function(){return"
"};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0){return""}}var out='"+text+"";return out};Renderer.prototype.image=function(href,title,text){var out='
";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:
"+escape(e.message+"",true)+"
"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());
--------------------------------------------------------------------------------
/static/js/vue.js:
--------------------------------------------------------------------------------
1 | /*
2 | Vue.js v0.10.3
3 | (c) 2014 Evan You
4 | License: MIT
5 | */
6 | ;(function(){
7 | 'use strict';
8 |
9 | /**
10 | * Require the given path.
11 | *
12 | * @param {String} path
13 | * @return {Object} exports
14 | * @api public
15 | */
16 |
17 | function require(path, parent, orig) {
18 | var resolved = require.resolve(path);
19 |
20 | // lookup failed
21 | if (null == resolved) {
22 | throwError()
23 | return
24 | }
25 |
26 | var module = require.modules[resolved];
27 |
28 | // perform real require()
29 | // by invoking the module's
30 | // registered function
31 | if (!module._resolving && !module.exports) {
32 | var mod = {};
33 | mod.exports = {};
34 | mod.client = mod.component = true;
35 | module._resolving = true;
36 | module.call(this, mod.exports, require.relative(resolved), mod);
37 | delete module._resolving;
38 | module.exports = mod.exports;
39 | }
40 |
41 | function throwError () {
42 | orig = orig || path;
43 | parent = parent || 'root';
44 | var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
45 | err.path = orig;
46 | err.parent = parent;
47 | err.require = true;
48 | throw err;
49 | }
50 |
51 | return module.exports;
52 | }
53 |
54 | /**
55 | * Registered modules.
56 | */
57 |
58 | require.modules = {};
59 |
60 | /**
61 | * Registered aliases.
62 | */
63 |
64 | require.aliases = {};
65 |
66 | /**
67 | * Resolve `path`.
68 | *
69 | * Lookup:
70 | *
71 | * - PATH/index.js
72 | * - PATH.js
73 | * - PATH
74 | *
75 | * @param {String} path
76 | * @return {String} path or null
77 | * @api private
78 | */
79 |
80 | require.exts = [
81 | '',
82 | '.js',
83 | '.json',
84 | '/index.js',
85 | '/index.json'
86 | ];
87 |
88 | require.resolve = function(path) {
89 | if (path.charAt(0) === '/') path = path.slice(1);
90 |
91 | for (var i = 0; i < 5; i++) {
92 | var fullPath = path + require.exts[i];
93 | if (require.modules.hasOwnProperty(fullPath)) return fullPath;
94 | if (require.aliases.hasOwnProperty(fullPath)) return require.aliases[fullPath];
95 | }
96 | };
97 |
98 | /**
99 | * Normalize `path` relative to the current path.
100 | *
101 | * @param {String} curr
102 | * @param {String} path
103 | * @return {String}
104 | * @api private
105 | */
106 |
107 | require.normalize = function(curr, path) {
108 |
109 | var segs = [];
110 |
111 | if ('.' != path.charAt(0)) return path;
112 |
113 | curr = curr.split('/');
114 | path = path.split('/');
115 |
116 | for (var i = 0; i < path.length; ++i) {
117 | if ('..' === path[i]) {
118 | curr.pop();
119 | } else if ('.' != path[i] && '' != path[i]) {
120 | segs.push(path[i]);
121 | }
122 | }
123 | return curr.concat(segs).join('/');
124 | };
125 |
126 | /**
127 | * Register module at `path` with callback `definition`.
128 | *
129 | * @param {String} path
130 | * @param {Function} definition
131 | * @api private
132 | */
133 |
134 | require.register = function(path, definition) {
135 | require.modules[path] = definition;
136 | };
137 |
138 | /**
139 | * Alias a module definition.
140 | *
141 | * @param {String} from
142 | * @param {String} to
143 | * @api private
144 | */
145 |
146 | require.alias = function(from, to) {
147 | if (!require.modules.hasOwnProperty(from)) {
148 | throwError()
149 | return
150 | }
151 | require.aliases[to] = from;
152 |
153 | function throwError () {
154 | throw new Error('Failed to alias "' + from + '", it does not exist');
155 | }
156 | };
157 |
158 | /**
159 | * Return a require function relative to the `parent` path.
160 | *
161 | * @param {String} parent
162 | * @return {Function}
163 | * @api private
164 | */
165 |
166 | require.relative = function(parent) {
167 | var p = require.normalize(parent, '..');
168 |
169 | /**
170 | * The relative require() itself.
171 | */
172 |
173 | function localRequire(path) {
174 | var resolved = localRequire.resolve(path);
175 | return require(resolved, parent, path);
176 | }
177 |
178 | /**
179 | * Resolve relative to the parent.
180 | */
181 |
182 | localRequire.resolve = function(path) {
183 | var c = path.charAt(0);
184 | if ('/' === c) return path.slice(1);
185 | if ('.' === c) return require.normalize(p, path);
186 |
187 | // resolve deps by returning
188 | // the dep in the nearest "deps"
189 | // directory
190 | var segs = parent.split('/');
191 | var i = segs.length;
192 | while (i--) {
193 | if (segs[i] === 'deps') {
194 | break;
195 | }
196 | }
197 | path = segs.slice(0, i + 2).join('/') + '/deps/' + path;
198 | return path;
199 | };
200 |
201 | /**
202 | * Check if module is defined at `path`.
203 | */
204 |
205 | localRequire.exists = function(path) {
206 | return require.modules.hasOwnProperty(localRequire.resolve(path));
207 | };
208 |
209 | return localRequire;
210 | };
211 | require.register("vue/src/main.js", function(exports, require, module){
212 | var config = require('./config'),
213 | ViewModel = require('./viewmodel'),
214 | utils = require('./utils'),
215 | makeHash = utils.hash,
216 | assetTypes = ['directive', 'filter', 'partial', 'effect', 'component']
217 |
218 | // require these so Browserify can catch them
219 | // so they can be used in Vue.require
220 | require('./observer')
221 | require('./transition')
222 |
223 | ViewModel.options = config.globalAssets = {
224 | directives : require('./directives'),
225 | filters : require('./filters'),
226 | partials : makeHash(),
227 | effects : makeHash(),
228 | components : makeHash()
229 | }
230 |
231 | /**
232 | * Expose asset registration methods
233 | */
234 | assetTypes.forEach(function (type) {
235 | ViewModel[type] = function (id, value) {
236 | var hash = this.options[type + 's']
237 | if (!hash) {
238 | hash = this.options[type + 's'] = makeHash()
239 | }
240 | if (!value) return hash[id]
241 | if (type === 'partial') {
242 | value = utils.toFragment(value)
243 | } else if (type === 'component') {
244 | value = utils.toConstructor(value)
245 | } else if (type === 'filter') {
246 | utils.checkFilter(value)
247 | }
248 | hash[id] = value
249 | return this
250 | }
251 | })
252 |
253 | /**
254 | * Set config options
255 | */
256 | ViewModel.config = function (opts, val) {
257 | if (typeof opts === 'string') {
258 | if (val === undefined) {
259 | return config[opts]
260 | } else {
261 | config[opts] = val
262 | }
263 | } else {
264 | utils.extend(config, opts)
265 | }
266 | return this
267 | }
268 |
269 | /**
270 | * Expose an interface for plugins
271 | */
272 | ViewModel.use = function (plugin) {
273 | if (typeof plugin === 'string') {
274 | try {
275 | plugin = require(plugin)
276 | } catch (e) {
277 | utils.warn('Cannot find plugin: ' + plugin)
278 | return
279 | }
280 | }
281 |
282 | // additional parameters
283 | var args = [].slice.call(arguments, 1)
284 | args.unshift(this)
285 |
286 | if (typeof plugin.install === 'function') {
287 | plugin.install.apply(plugin, args)
288 | } else {
289 | plugin.apply(null, args)
290 | }
291 | return this
292 | }
293 |
294 | /**
295 | * Expose internal modules for plugins
296 | */
297 | ViewModel.require = function (path) {
298 | return require('./' + path)
299 | }
300 |
301 | ViewModel.extend = extend
302 | ViewModel.nextTick = utils.nextTick
303 |
304 | /**
305 | * Expose the main ViewModel class
306 | * and add extend method
307 | */
308 | function extend (options) {
309 |
310 | var ParentVM = this
311 |
312 | // extend data options need to be copied
313 | // on instantiation
314 | if (options.data) {
315 | options.defaultData = options.data
316 | delete options.data
317 | }
318 |
319 | // inherit options
320 | options = inheritOptions(options, ParentVM.options, true)
321 | utils.processOptions(options)
322 |
323 | var ExtendedVM = function (opts, asParent) {
324 | if (!asParent) {
325 | opts = inheritOptions(opts, options, true)
326 | }
327 | ParentVM.call(this, opts, true)
328 | }
329 |
330 | // inherit prototype props
331 | var proto = ExtendedVM.prototype = Object.create(ParentVM.prototype)
332 | utils.defProtected(proto, 'constructor', ExtendedVM)
333 |
334 | // allow extended VM to be further extended
335 | ExtendedVM.extend = extend
336 | ExtendedVM.super = ParentVM
337 | ExtendedVM.options = options
338 |
339 | // allow extended VM to add its own assets
340 | assetTypes.forEach(function (type) {
341 | ExtendedVM[type] = ViewModel[type]
342 | })
343 |
344 | // allow extended VM to use plugins
345 | ExtendedVM.use = ViewModel.use
346 | ExtendedVM.require = ViewModel.require
347 |
348 | return ExtendedVM
349 | }
350 |
351 | /**
352 | * Inherit options
353 | *
354 | * For options such as `data`, `vms`, `directives`, 'partials',
355 | * they should be further extended. However extending should only
356 | * be done at top level.
357 | *
358 | * `proto` is an exception because it's handled directly on the
359 | * prototype.
360 | *
361 | * `el` is an exception because it's not allowed as an
362 | * extension option, but only as an instance option.
363 | */
364 | function inheritOptions (child, parent, topLevel) {
365 | child = child || {}
366 | if (!parent) return child
367 | for (var key in parent) {
368 | if (key === 'el') continue
369 | var val = child[key],
370 | parentVal = parent[key]
371 | if (topLevel && typeof val === 'function' && parentVal) {
372 | // merge hook functions into an array
373 | child[key] = [val]
374 | if (Array.isArray(parentVal)) {
375 | child[key] = child[key].concat(parentVal)
376 | } else {
377 | child[key].push(parentVal)
378 | }
379 | } else if (
380 | topLevel &&
381 | (utils.isTrueObject(val) || utils.isTrueObject(parentVal))
382 | && !(parentVal instanceof ViewModel)
383 | ) {
384 | // merge toplevel object options
385 | child[key] = inheritOptions(val, parentVal)
386 | } else if (val === undefined) {
387 | // inherit if child doesn't override
388 | child[key] = parentVal
389 | }
390 | }
391 | return child
392 | }
393 |
394 | module.exports = ViewModel
395 | });
396 | require.register("vue/src/emitter.js", function(exports, require, module){
397 | function Emitter (ctx) {
398 | this._ctx = ctx || this
399 | }
400 |
401 | var EmitterProto = Emitter.prototype
402 |
403 | EmitterProto.on = function(event, fn){
404 | this._cbs = this._cbs || {}
405 | ;(this._cbs[event] = this._cbs[event] || [])
406 | .push(fn)
407 | return this
408 | }
409 |
410 | EmitterProto.once = function(event, fn){
411 | var self = this
412 | this._cbs = this._cbs || {}
413 |
414 | function on () {
415 | self.off(event, on)
416 | fn.apply(this, arguments)
417 | }
418 |
419 | on.fn = fn
420 | this.on(event, on)
421 | return this
422 | }
423 |
424 | EmitterProto.off = function(event, fn){
425 | this._cbs = this._cbs || {}
426 |
427 | // all
428 | if (!arguments.length) {
429 | this._cbs = {}
430 | return this
431 | }
432 |
433 | // specific event
434 | var callbacks = this._cbs[event]
435 | if (!callbacks) return this
436 |
437 | // remove all handlers
438 | if (arguments.length === 1) {
439 | delete this._cbs[event]
440 | return this
441 | }
442 |
443 | // remove specific handler
444 | var cb
445 | for (var i = 0; i < callbacks.length; i++) {
446 | cb = callbacks[i]
447 | if (cb === fn || cb.fn === fn) {
448 | callbacks.splice(i, 1)
449 | break
450 | }
451 | }
452 | return this
453 | }
454 |
455 | EmitterProto.emit = function(event, a, b, c){
456 | this._cbs = this._cbs || {}
457 | var callbacks = this._cbs[event]
458 |
459 | if (callbacks) {
460 | callbacks = callbacks.slice(0)
461 | for (var i = 0, len = callbacks.length; i < len; i++) {
462 | callbacks[i].call(this._ctx, a, b, c)
463 | }
464 | }
465 |
466 | return this
467 | }
468 |
469 | module.exports = Emitter
470 | });
471 | require.register("vue/src/config.js", function(exports, require, module){
472 | var TextParser = require('./text-parser')
473 |
474 | module.exports = {
475 | prefix : 'v',
476 | debug : false,
477 | silent : false,
478 | enterClass : 'v-enter',
479 | leaveClass : 'v-leave',
480 | interpolate : true
481 | }
482 |
483 | Object.defineProperty(module.exports, 'delimiters', {
484 | get: function () {
485 | return TextParser.delimiters
486 | },
487 | set: function (delimiters) {
488 | TextParser.setDelimiters(delimiters)
489 | }
490 | })
491 | });
492 | require.register("vue/src/utils.js", function(exports, require, module){
493 | var config = require('./config'),
494 | toString = ({}).toString,
495 | win = window,
496 | console = win.console,
497 | timeout = win.setTimeout,
498 | def = Object.defineProperty,
499 | THIS_RE = /[^\w]this[^\w]/,
500 | OBJECT = 'object',
501 | hasClassList = 'classList' in document.documentElement,
502 | ViewModel // late def
503 |
504 | var utils = module.exports = {
505 |
506 | /**
507 | * get a value from an object keypath
508 | */
509 | get: function (obj, key) {
510 | /* jshint eqeqeq: false */
511 | if (key.indexOf('.') < 0) {
512 | return obj[key]
513 | }
514 | var path = key.split('.'),
515 | d = -1, l = path.length
516 | while (++d < l && obj != null) {
517 | obj = obj[path[d]]
518 | }
519 | return obj
520 | },
521 |
522 | /**
523 | * set a value to an object keypath
524 | */
525 | set: function (obj, key, val) {
526 | /* jshint eqeqeq: false */
527 | if (key.indexOf('.') < 0) {
528 | obj[key] = val
529 | return
530 | }
531 | var path = key.split('.'),
532 | d = -1, l = path.length - 1
533 | while (++d < l) {
534 | if (obj[path[d]] == null) {
535 | obj[path[d]] = {}
536 | }
537 | obj = obj[path[d]]
538 | }
539 | obj[path[d]] = val
540 | },
541 |
542 | /**
543 | * return the base segment of a keypath
544 | */
545 | baseKey: function (key) {
546 | return key.indexOf('.') > 0
547 | ? key.split('.')[0]
548 | : key
549 | },
550 |
551 | /**
552 | * Create a prototype-less object
553 | * which is a better hash/map
554 | */
555 | hash: function () {
556 | return Object.create(null)
557 | },
558 |
559 | /**
560 | * get an attribute and remove it.
561 | */
562 | attr: function (el, type) {
563 | var attr = config.prefix + '-' + type,
564 | val = el.getAttribute(attr)
565 | if (val !== null) {
566 | el.removeAttribute(attr)
567 | }
568 | return val
569 | },
570 |
571 | /**
572 | * Define an ienumerable property
573 | * This avoids it being included in JSON.stringify
574 | * or for...in loops.
575 | */
576 | defProtected: function (obj, key, val, enumerable, writable) {
577 | def(obj, key, {
578 | value : val,
579 | enumerable : enumerable,
580 | writable : writable,
581 | configurable : true
582 | })
583 | },
584 |
585 | /**
586 | * A less bullet-proof but more efficient type check
587 | * than Object.prototype.toString
588 | */
589 | isObject: function (obj) {
590 | return typeof obj === OBJECT && obj && !Array.isArray(obj)
591 | },
592 |
593 | /**
594 | * A more accurate but less efficient type check
595 | */
596 | isTrueObject: function (obj) {
597 | return toString.call(obj) === '[object Object]'
598 | },
599 |
600 | /**
601 | * Most simple bind
602 | * enough for the usecase and fast than native bind()
603 | */
604 | bind: function (fn, ctx) {
605 | return function (arg) {
606 | return fn.call(ctx, arg)
607 | }
608 | },
609 |
610 | /**
611 | * Make sure null and undefined output empty string
612 | */
613 | guard: function (value) {
614 | /* jshint eqeqeq: false, eqnull: true */
615 | return value == null
616 | ? ''
617 | : (typeof value == 'object')
618 | ? JSON.stringify(value)
619 | : value
620 | },
621 |
622 | /**
623 | * When setting value on the VM, parse possible numbers
624 | */
625 | checkNumber: function (value) {
626 | return (isNaN(value) || value === null || typeof value === 'boolean')
627 | ? value
628 | : Number(value)
629 | },
630 |
631 | /**
632 | * simple extend
633 | */
634 | extend: function (obj, ext) {
635 | for (var key in ext) {
636 | if (obj[key] !== ext[key]) {
637 | obj[key] = ext[key]
638 | }
639 | }
640 | return obj
641 | },
642 |
643 | /**
644 | * filter an array with duplicates into uniques
645 | */
646 | unique: function (arr) {
647 | var hash = utils.hash(),
648 | i = arr.length,
649 | key, res = []
650 | while (i--) {
651 | key = arr[i]
652 | if (hash[key]) continue
653 | hash[key] = 1
654 | res.push(key)
655 | }
656 | return res
657 | },
658 |
659 | /**
660 | * Convert a string template to a dom fragment
661 | */
662 | toFragment: function (template) {
663 | if (typeof template !== 'string') {
664 | return template
665 | }
666 | if (template.charAt(0) === '#') {
667 | var templateNode = document.getElementById(template.slice(1))
668 | if (!templateNode) return
669 | // if its a template tag and the browser supports it,
670 | // its content is already a document fragment!
671 | if (templateNode.tagName === 'TEMPLATE' && templateNode.content) {
672 | return templateNode.content
673 | }
674 | template = templateNode.innerHTML
675 | }
676 | var node = document.createElement('div'),
677 | frag = document.createDocumentFragment(),
678 | child
679 | node.innerHTML = template.trim()
680 | /* jshint boss: true */
681 | while (child = node.firstChild) {
682 | if (node.nodeType === 1) {
683 | frag.appendChild(child)
684 | }
685 | }
686 | return frag
687 | },
688 |
689 | /**
690 | * Convert the object to a ViewModel constructor
691 | * if it is not already one
692 | */
693 | toConstructor: function (obj) {
694 | ViewModel = ViewModel || require('./viewmodel')
695 | return utils.isObject(obj)
696 | ? ViewModel.extend(obj)
697 | : typeof obj === 'function'
698 | ? obj
699 | : null
700 | },
701 |
702 | /**
703 | * Check if a filter function contains references to `this`
704 | * If yes, mark it as a computed filter.
705 | */
706 | checkFilter: function (filter) {
707 | if (THIS_RE.test(filter.toString())) {
708 | filter.computed = true
709 | }
710 | },
711 |
712 | /**
713 | * convert certain option values to the desired format.
714 | */
715 | processOptions: function (options) {
716 | var components = options.components,
717 | partials = options.partials,
718 | template = options.template,
719 | filters = options.filters,
720 | key
721 | if (components) {
722 | for (key in components) {
723 | components[key] = utils.toConstructor(components[key])
724 | }
725 | }
726 | if (partials) {
727 | for (key in partials) {
728 | partials[key] = utils.toFragment(partials[key])
729 | }
730 | }
731 | if (filters) {
732 | for (key in filters) {
733 | utils.checkFilter(filters[key])
734 | }
735 | }
736 | if (template) {
737 | options.template = utils.toFragment(template)
738 | }
739 | },
740 |
741 | /**
742 | * used to defer batch updates
743 | */
744 | nextTick: function (cb) {
745 | timeout(cb, 0)
746 | },
747 |
748 | /**
749 | * add class for IE9
750 | * uses classList if available
751 | */
752 | addClass: function (el, cls) {
753 | if (hasClassList) {
754 | el.classList.add(cls)
755 | } else {
756 | var cur = ' ' + el.className + ' '
757 | if (cur.indexOf(' ' + cls + ' ') < 0) {
758 | el.className = (cur + cls).trim()
759 | }
760 | }
761 | },
762 |
763 | /**
764 | * remove class for IE9
765 | */
766 | removeClass: function (el, cls) {
767 | if (hasClassList) {
768 | el.classList.remove(cls)
769 | } else {
770 | var cur = ' ' + el.className + ' ',
771 | tar = ' ' + cls + ' '
772 | while (cur.indexOf(tar) >= 0) {
773 | cur = cur.replace(tar, ' ')
774 | }
775 | el.className = cur.trim()
776 | }
777 | },
778 |
779 | /**
780 | * Convert an object to Array
781 | * used in v-repeat and array filters
782 | */
783 | objectToArray: function (obj) {
784 | var res = [], val, data
785 | for (var key in obj) {
786 | val = obj[key]
787 | data = utils.isObject(val)
788 | ? val
789 | : { $value: val }
790 | data.$key = key
791 | res.push(data)
792 | }
793 | return res
794 | }
795 | }
796 |
797 | enableDebug()
798 | function enableDebug () {
799 | /**
800 | * log for debugging
801 | */
802 | utils.log = function (msg) {
803 | if (config.debug && console) {
804 | console.log(msg)
805 | }
806 | }
807 |
808 | /**
809 | * warnings, traces by default
810 | * can be suppressed by `silent` option.
811 | */
812 | utils.warn = function (msg) {
813 | if (!config.silent && console) {
814 | console.warn(msg)
815 | if (config.debug && console.trace) {
816 | console.trace()
817 | }
818 | }
819 | }
820 | }
821 | });
822 | require.register("vue/src/compiler.js", function(exports, require, module){
823 | var Emitter = require('./emitter'),
824 | Observer = require('./observer'),
825 | config = require('./config'),
826 | utils = require('./utils'),
827 | Binding = require('./binding'),
828 | Directive = require('./directive'),
829 | TextParser = require('./text-parser'),
830 | DepsParser = require('./deps-parser'),
831 | ExpParser = require('./exp-parser'),
832 | ViewModel,
833 |
834 | // cache methods
835 | slice = [].slice,
836 | extend = utils.extend,
837 | hasOwn = ({}).hasOwnProperty,
838 | def = Object.defineProperty,
839 |
840 | // hooks to register
841 | hooks = [
842 | 'created', 'ready',
843 | 'beforeDestroy', 'afterDestroy',
844 | 'attached', 'detached'
845 | ],
846 |
847 | // list of priority directives
848 | // that needs to be checked in specific order
849 | priorityDirectives = [
850 | 'if',
851 | 'repeat',
852 | 'view',
853 | 'component'
854 | ]
855 |
856 | /**
857 | * The DOM compiler
858 | * scans a DOM node and compile bindings for a ViewModel
859 | */
860 | function Compiler (vm, options) {
861 |
862 | var compiler = this,
863 | key, i
864 |
865 | // default state
866 | compiler.init = true
867 | compiler.destroyed = false
868 |
869 | // process and extend options
870 | options = compiler.options = options || {}
871 | utils.processOptions(options)
872 |
873 | // copy compiler options
874 | extend(compiler, options.compilerOptions)
875 | // repeat indicates this is a v-repeat instance
876 | compiler.repeat = compiler.repeat || false
877 | // expCache will be shared between v-repeat instances
878 | compiler.expCache = compiler.expCache || {}
879 |
880 | // initialize element
881 | var el = compiler.el = compiler.setupElement(options)
882 | utils.log('\nnew VM instance: ' + el.tagName + '\n')
883 |
884 | // set other compiler properties
885 | compiler.vm = el.vue_vm = vm
886 | compiler.bindings = utils.hash()
887 | compiler.dirs = []
888 | compiler.deferred = []
889 | compiler.computed = []
890 | compiler.children = []
891 | compiler.emitter = new Emitter(vm)
892 |
893 | // create bindings for computed properties
894 | if (options.methods) {
895 | for (key in options.methods) {
896 | compiler.createBinding(key)
897 | }
898 | }
899 |
900 | // create bindings for methods
901 | if (options.computed) {
902 | for (key in options.computed) {
903 | compiler.createBinding(key)
904 | }
905 | }
906 |
907 | // VM ---------------------------------------------------------------------
908 |
909 | // set VM properties
910 | vm.$ = {}
911 | vm.$el = el
912 | vm.$options = options
913 | vm.$compiler = compiler
914 | vm.$event = null
915 |
916 | // set parent & root
917 | var parentVM = options.parent
918 | if (parentVM) {
919 | compiler.parent = parentVM.$compiler
920 | parentVM.$compiler.children.push(compiler)
921 | vm.$parent = parentVM
922 | }
923 | vm.$root = getRoot(compiler).vm
924 |
925 | // DATA -------------------------------------------------------------------
926 |
927 | // setup observer
928 | // this is necesarry for all hooks and data observation events
929 | compiler.setupObserver()
930 |
931 | // initialize data
932 | var data = compiler.data = options.data || {},
933 | defaultData = options.defaultData
934 | if (defaultData) {
935 | for (key in defaultData) {
936 | if (!hasOwn.call(data, key)) {
937 | data[key] = defaultData[key]
938 | }
939 | }
940 | }
941 |
942 | // copy paramAttributes
943 | var params = options.paramAttributes
944 | if (params) {
945 | i = params.length
946 | while (i--) {
947 | data[params[i]] = utils.checkNumber(
948 | compiler.eval(
949 | el.getAttribute(params[i])
950 | )
951 | )
952 | }
953 | }
954 |
955 | // copy data properties to vm
956 | // so user can access them in the created hook
957 | extend(vm, data)
958 | vm.$data = data
959 |
960 | // beforeCompile hook
961 | compiler.execHook('created')
962 |
963 | // the user might have swapped the data ...
964 | data = compiler.data = vm.$data
965 |
966 | // user might also set some properties on the vm
967 | // in which case we should copy back to $data
968 | var vmProp
969 | for (key in vm) {
970 | vmProp = vm[key]
971 | if (
972 | key.charAt(0) !== '$' &&
973 | data[key] !== vmProp &&
974 | typeof vmProp !== 'function'
975 | ) {
976 | data[key] = vmProp
977 | }
978 | }
979 |
980 | // now we can observe the data.
981 | // this will convert data properties to getter/setters
982 | // and emit the first batch of set events, which will
983 | // in turn create the corresponding bindings.
984 | compiler.observeData(data)
985 |
986 | // COMPILE ----------------------------------------------------------------
987 |
988 | // before compiling, resolve content insertion points
989 | if (options.template) {
990 | this.resolveContent()
991 | }
992 |
993 | // now parse the DOM and bind directives.
994 | // During this stage, we will also create bindings for
995 | // encountered keypaths that don't have a binding yet.
996 | compiler.compile(el, true)
997 |
998 | // Any directive that creates child VMs are deferred
999 | // so that when they are compiled, all bindings on the
1000 | // parent VM have been created.
1001 | i = compiler.deferred.length
1002 | while (i--) {
1003 | compiler.bindDirective(compiler.deferred[i])
1004 | }
1005 | compiler.deferred = null
1006 |
1007 | // extract dependencies for computed properties.
1008 | // this will evaluated all collected computed bindings
1009 | // and collect get events that are emitted.
1010 | if (this.computed.length) {
1011 | DepsParser.parse(this.computed)
1012 | }
1013 |
1014 | // done!
1015 | compiler.init = false
1016 |
1017 | // post compile / ready hook
1018 | compiler.execHook('ready')
1019 | }
1020 |
1021 | var CompilerProto = Compiler.prototype
1022 |
1023 | /**
1024 | * Initialize the VM/Compiler's element.
1025 | * Fill it in with the template if necessary.
1026 | */
1027 | CompilerProto.setupElement = function (options) {
1028 | // create the node first
1029 | var el = typeof options.el === 'string'
1030 | ? document.querySelector(options.el)
1031 | : options.el || document.createElement(options.tagName || 'div')
1032 |
1033 | var template = options.template,
1034 | child, replacer, i, attr, attrs
1035 |
1036 | if (template) {
1037 | // collect anything already in there
1038 | if (el.hasChildNodes()) {
1039 | this.rawContent = document.createElement('div')
1040 | /* jshint boss: true */
1041 | while (child = el.firstChild) {
1042 | this.rawContent.appendChild(child)
1043 | }
1044 | }
1045 | // replace option: use the first node in
1046 | // the template directly
1047 | if (options.replace && template.childNodes.length === 1) {
1048 | replacer = template.childNodes[0].cloneNode(true)
1049 | if (el.parentNode) {
1050 | el.parentNode.insertBefore(replacer, el)
1051 | el.parentNode.removeChild(el)
1052 | }
1053 | // copy over attributes
1054 | if (el.hasAttributes()) {
1055 | i = el.attributes.length
1056 | while (i--) {
1057 | attr = el.attributes[i]
1058 | replacer.setAttribute(attr.name, attr.value)
1059 | }
1060 | }
1061 | // replace
1062 | el = replacer
1063 | } else {
1064 | el.appendChild(template.cloneNode(true))
1065 | }
1066 |
1067 | }
1068 |
1069 | // apply element options
1070 | if (options.id) el.id = options.id
1071 | if (options.className) el.className = options.className
1072 | attrs = options.attributes
1073 | if (attrs) {
1074 | for (attr in attrs) {
1075 | el.setAttribute(attr, attrs[attr])
1076 | }
1077 | }
1078 |
1079 | return el
1080 | }
1081 |
1082 | /**
1083 | * Deal with insertion points
1084 | * per the Web Components spec
1085 | */
1086 | CompilerProto.resolveContent = function () {
1087 |
1088 | var outlets = slice.call(this.el.getElementsByTagName('content')),
1089 | raw = this.rawContent,
1090 | outlet, select, i, j, main
1091 |
1092 | i = outlets.length
1093 | if (i) {
1094 | // first pass, collect corresponding content
1095 | // for each outlet.
1096 | while (i--) {
1097 | outlet = outlets[i]
1098 | if (raw) {
1099 | select = outlet.getAttribute('select')
1100 | if (select) { // select content
1101 | outlet.content =
1102 | slice.call(raw.querySelectorAll(select))
1103 | } else { // default content
1104 | main = outlet
1105 | }
1106 | } else { // fallback content
1107 | outlet.content =
1108 | slice.call(outlet.childNodes)
1109 | }
1110 | }
1111 | // second pass, actually insert the contents
1112 | for (i = 0, j = outlets.length; i < j; i++) {
1113 | outlet = outlets[i]
1114 | if (outlet === main) continue
1115 | insert(outlet, outlet.content)
1116 | }
1117 | // finally insert the main content
1118 | if (raw && main) {
1119 | insert(main, slice.call(raw.childNodes))
1120 | }
1121 | }
1122 |
1123 | function insert (outlet, contents) {
1124 | var parent = outlet.parentNode,
1125 | i = 0, j = contents.length
1126 | for (; i < j; i++) {
1127 | parent.insertBefore(contents[i], outlet)
1128 | }
1129 | parent.removeChild(outlet)
1130 | }
1131 |
1132 | this.rawContent = null
1133 | }
1134 |
1135 | /**
1136 | * Setup observer.
1137 | * The observer listens for get/set/mutate events on all VM
1138 | * values/objects and trigger corresponding binding updates.
1139 | * It also listens for lifecycle hooks.
1140 | */
1141 | CompilerProto.setupObserver = function () {
1142 |
1143 | var compiler = this,
1144 | bindings = compiler.bindings,
1145 | options = compiler.options,
1146 | observer = compiler.observer = new Emitter(compiler.vm)
1147 |
1148 | // a hash to hold event proxies for each root level key
1149 | // so they can be referenced and removed later
1150 | observer.proxies = {}
1151 |
1152 | // add own listeners which trigger binding updates
1153 | observer
1154 | .on('get', onGet)
1155 | .on('set', onSet)
1156 | .on('mutate', onSet)
1157 |
1158 | // register hooks
1159 | var i = hooks.length, j, hook, fns
1160 | while (i--) {
1161 | hook = hooks[i]
1162 | fns = options[hook]
1163 | if (Array.isArray(fns)) {
1164 | j = fns.length
1165 | // since hooks were merged with child at head,
1166 | // we loop reversely.
1167 | while (j--) {
1168 | registerHook(hook, fns[j])
1169 | }
1170 | } else if (fns) {
1171 | registerHook(hook, fns)
1172 | }
1173 | }
1174 |
1175 | // broadcast attached/detached hooks
1176 | observer
1177 | .on('hook:attached', function () {
1178 | broadcast(1)
1179 | })
1180 | .on('hook:detached', function () {
1181 | broadcast(0)
1182 | })
1183 |
1184 | function onGet (key) {
1185 | check(key)
1186 | DepsParser.catcher.emit('get', bindings[key])
1187 | }
1188 |
1189 | function onSet (key, val, mutation) {
1190 | observer.emit('change:' + key, val, mutation)
1191 | check(key)
1192 | bindings[key].update(val)
1193 | }
1194 |
1195 | function registerHook (hook, fn) {
1196 | observer.on('hook:' + hook, function () {
1197 | fn.call(compiler.vm)
1198 | })
1199 | }
1200 |
1201 | function broadcast (event) {
1202 | var children = compiler.children
1203 | if (children) {
1204 | var child, i = children.length
1205 | while (i--) {
1206 | child = children[i]
1207 | if (child.el.parentNode) {
1208 | event = 'hook:' + (event ? 'attached' : 'detached')
1209 | child.observer.emit(event)
1210 | child.emitter.emit(event)
1211 | }
1212 | }
1213 | }
1214 | }
1215 |
1216 | function check (key) {
1217 | if (!bindings[key]) {
1218 | compiler.createBinding(key)
1219 | }
1220 | }
1221 | }
1222 |
1223 | CompilerProto.observeData = function (data) {
1224 |
1225 | var compiler = this,
1226 | observer = compiler.observer
1227 |
1228 | // recursively observe nested properties
1229 | Observer.observe(data, '', observer)
1230 |
1231 | // also create binding for top level $data
1232 | // so it can be used in templates too
1233 | var $dataBinding = compiler.bindings['$data'] = new Binding(compiler, '$data')
1234 | $dataBinding.update(data)
1235 |
1236 | // allow $data to be swapped
1237 | def(compiler.vm, '$data', {
1238 | get: function () {
1239 | compiler.observer.emit('get', '$data')
1240 | return compiler.data
1241 | },
1242 | set: function (newData) {
1243 | var oldData = compiler.data
1244 | Observer.unobserve(oldData, '', observer)
1245 | compiler.data = newData
1246 | Observer.copyPaths(newData, oldData)
1247 | Observer.observe(newData, '', observer)
1248 | update()
1249 | }
1250 | })
1251 |
1252 | // emit $data change on all changes
1253 | observer
1254 | .on('set', onSet)
1255 | .on('mutate', onSet)
1256 |
1257 | function onSet (key) {
1258 | if (key !== '$data') update()
1259 | }
1260 |
1261 | function update () {
1262 | $dataBinding.update(compiler.data)
1263 | observer.emit('change:$data', compiler.data)
1264 | }
1265 | }
1266 |
1267 | /**
1268 | * Compile a DOM node (recursive)
1269 | */
1270 | CompilerProto.compile = function (node, root) {
1271 | var nodeType = node.nodeType
1272 | if (nodeType === 1 && node.tagName !== 'SCRIPT') { // a normal node
1273 | this.compileElement(node, root)
1274 | } else if (nodeType === 3 && config.interpolate) {
1275 | this.compileTextNode(node)
1276 | }
1277 | }
1278 |
1279 | /**
1280 | * Check for a priority directive
1281 | * If it is present and valid, return true to skip the rest
1282 | */
1283 | CompilerProto.checkPriorityDir = function (dirname, node, root) {
1284 | var expression, directive, Ctor
1285 | if (
1286 | dirname === 'component' &&
1287 | root !== true &&
1288 | (Ctor = this.resolveComponent(node, undefined, true))
1289 | ) {
1290 | directive = this.parseDirective(dirname, '', node)
1291 | directive.Ctor = Ctor
1292 | } else {
1293 | expression = utils.attr(node, dirname)
1294 | directive = expression && this.parseDirective(dirname, expression, node)
1295 | }
1296 | if (directive) {
1297 | if (root === true) {
1298 | utils.warn(
1299 | 'Directive v-' + dirname + ' cannot be used on an already instantiated ' +
1300 | 'VM\'s root node. Use it from the parent\'s template instead.'
1301 | )
1302 | return
1303 | }
1304 | this.deferred.push(directive)
1305 | return true
1306 | }
1307 | }
1308 |
1309 | /**
1310 | * Compile normal directives on a node
1311 | */
1312 | CompilerProto.compileElement = function (node, root) {
1313 |
1314 | // textarea is pretty annoying
1315 | // because its value creates childNodes which
1316 | // we don't want to compile.
1317 | if (node.tagName === 'TEXTAREA' && node.value) {
1318 | node.value = this.eval(node.value)
1319 | }
1320 |
1321 | // only compile if this element has attributes
1322 | // or its tagName contains a hyphen (which means it could
1323 | // potentially be a custom element)
1324 | if (node.hasAttributes() || node.tagName.indexOf('-') > -1) {
1325 |
1326 | // skip anything with v-pre
1327 | if (utils.attr(node, 'pre') !== null) {
1328 | return
1329 | }
1330 |
1331 | var i, l, j, k
1332 |
1333 | // check priority directives.
1334 | // if any of them are present, it will take over the node with a childVM
1335 | // so we can skip the rest
1336 | for (i = 0, l = priorityDirectives.length; i < l; i++) {
1337 | if (this.checkPriorityDir(priorityDirectives[i], node, root)) {
1338 | return
1339 | }
1340 | }
1341 |
1342 | // check transition & animation properties
1343 | node.vue_trans = utils.attr(node, 'transition')
1344 | node.vue_anim = utils.attr(node, 'animation')
1345 | node.vue_effect = this.eval(utils.attr(node, 'effect'))
1346 |
1347 | var prefix = config.prefix + '-',
1348 | attrs = slice.call(node.attributes),
1349 | params = this.options.paramAttributes,
1350 | attr, isDirective, exp, directives, directive, dirname
1351 |
1352 | for (i = 0, l = attrs.length; i < l; i++) {
1353 |
1354 | attr = attrs[i]
1355 | isDirective = false
1356 |
1357 | if (attr.name.indexOf(prefix) === 0) {
1358 | // a directive - split, parse and bind it.
1359 | isDirective = true
1360 | dirname = attr.name.slice(prefix.length)
1361 | // build with multiple: true
1362 | directives = this.parseDirective(dirname, attr.value, node, true)
1363 | // loop through clauses (separated by ",")
1364 | // inside each attribute
1365 | for (j = 0, k = directives.length; j < k; j++) {
1366 | directive = directives[j]
1367 | if (dirname === 'with') {
1368 | this.bindDirective(directive, this.parent)
1369 | } else {
1370 | this.bindDirective(directive)
1371 | }
1372 | }
1373 | } else if (config.interpolate) {
1374 | // non directive attribute, check interpolation tags
1375 | exp = TextParser.parseAttr(attr.value)
1376 | if (exp) {
1377 | directive = this.parseDirective('attr', attr.name + ':' + exp, node)
1378 | if (params && params.indexOf(attr.name) > -1) {
1379 | // a param attribute... we should use the parent binding
1380 | // to avoid circular updates like size={{size}}
1381 | this.bindDirective(directive, this.parent)
1382 | } else {
1383 | this.bindDirective(directive)
1384 | }
1385 | }
1386 | }
1387 |
1388 | if (isDirective && dirname !== 'cloak') {
1389 | node.removeAttribute(attr.name)
1390 | }
1391 | }
1392 |
1393 | }
1394 |
1395 | // recursively compile childNodes
1396 | if (node.hasChildNodes()) {
1397 | slice.call(node.childNodes).forEach(this.compile, this)
1398 | }
1399 | }
1400 |
1401 | /**
1402 | * Compile a text node
1403 | */
1404 | CompilerProto.compileTextNode = function (node) {
1405 |
1406 | var tokens = TextParser.parse(node.nodeValue)
1407 | if (!tokens) return
1408 | var el, token, directive
1409 |
1410 | for (var i = 0, l = tokens.length; i < l; i++) {
1411 |
1412 | token = tokens[i]
1413 | directive = null
1414 |
1415 | if (token.key) { // a binding
1416 | if (token.key.charAt(0) === '>') { // a partial
1417 | el = document.createComment('ref')
1418 | directive = this.parseDirective('partial', token.key.slice(1), el)
1419 | } else {
1420 | if (!token.html) { // text binding
1421 | el = document.createTextNode('')
1422 | directive = this.parseDirective('text', token.key, el)
1423 | } else { // html binding
1424 | el = document.createComment(config.prefix + '-html')
1425 | directive = this.parseDirective('html', token.key, el)
1426 | }
1427 | }
1428 | } else { // a plain string
1429 | el = document.createTextNode(token)
1430 | }
1431 |
1432 | // insert node
1433 | node.parentNode.insertBefore(el, node)
1434 | // bind directive
1435 | this.bindDirective(directive)
1436 |
1437 | }
1438 | node.parentNode.removeChild(node)
1439 | }
1440 |
1441 | /**
1442 | * Parse a directive name/value pair into one or more
1443 | * directive instances
1444 | */
1445 | CompilerProto.parseDirective = function (name, value, el, multiple) {
1446 | var compiler = this,
1447 | definition = compiler.getOption('directives', name)
1448 | if (definition) {
1449 | // parse into AST-like objects
1450 | var asts = Directive.parse(value)
1451 | return multiple
1452 | ? asts.map(build)
1453 | : build(asts[0])
1454 | }
1455 | function build (ast) {
1456 | return new Directive(name, ast, definition, compiler, el)
1457 | }
1458 | }
1459 |
1460 | /**
1461 | * Add a directive instance to the correct binding & viewmodel
1462 | */
1463 | CompilerProto.bindDirective = function (directive, bindingOwner) {
1464 |
1465 | if (!directive) return
1466 |
1467 | // keep track of it so we can unbind() later
1468 | this.dirs.push(directive)
1469 |
1470 | // for empty or literal directives, simply call its bind()
1471 | // and we're done.
1472 | if (directive.isEmpty || directive.isLiteral) {
1473 | if (directive.bind) directive.bind()
1474 | return
1475 | }
1476 |
1477 | // otherwise, we got more work to do...
1478 | var binding,
1479 | compiler = bindingOwner || this,
1480 | key = directive.key
1481 |
1482 | if (directive.isExp) {
1483 | // expression bindings are always created on current compiler
1484 | binding = compiler.createBinding(key, directive)
1485 | } else {
1486 | // recursively locate which compiler owns the binding
1487 | while (compiler) {
1488 | if (compiler.hasKey(key)) {
1489 | break
1490 | } else {
1491 | compiler = compiler.parent
1492 | }
1493 | }
1494 | compiler = compiler || this
1495 | binding = compiler.bindings[key] || compiler.createBinding(key)
1496 | }
1497 | binding.dirs.push(directive)
1498 | directive.binding = binding
1499 |
1500 | var value = binding.val()
1501 | // invoke bind hook if exists
1502 | if (directive.bind) {
1503 | directive.bind(value)
1504 | }
1505 | // set initial value
1506 | directive.update(value, true)
1507 | }
1508 |
1509 | /**
1510 | * Create binding and attach getter/setter for a key to the viewmodel object
1511 | */
1512 | CompilerProto.createBinding = function (key, directive) {
1513 |
1514 | utils.log(' created binding: ' + key)
1515 |
1516 | var compiler = this,
1517 | methods = compiler.options.methods,
1518 | isExp = directive && directive.isExp,
1519 | isFn = (directive && directive.isFn) || (methods && methods[key]),
1520 | bindings = compiler.bindings,
1521 | computed = compiler.options.computed,
1522 | binding = new Binding(compiler, key, isExp, isFn)
1523 |
1524 | if (isExp) {
1525 | // expression bindings are anonymous
1526 | compiler.defineExp(key, binding, directive)
1527 | } else if (isFn) {
1528 | bindings[key] = binding
1529 | binding.value = compiler.vm[key] = methods[key]
1530 | } else {
1531 | bindings[key] = binding
1532 | if (binding.root) {
1533 | // this is a root level binding. we need to define getter/setters for it.
1534 | if (computed && computed[key]) {
1535 | // computed property
1536 | compiler.defineComputed(key, binding, computed[key])
1537 | } else if (key.charAt(0) !== '$') {
1538 | // normal property
1539 | compiler.defineProp(key, binding)
1540 | } else {
1541 | compiler.defineMeta(key, binding)
1542 | }
1543 | } else if (computed && computed[utils.baseKey(key)]) {
1544 | // nested path on computed property
1545 | compiler.defineExp(key, binding)
1546 | } else {
1547 | // ensure path in data so that computed properties that
1548 | // access the path don't throw an error and can collect
1549 | // dependencies
1550 | Observer.ensurePath(compiler.data, key)
1551 | var parentKey = key.slice(0, key.lastIndexOf('.'))
1552 | if (!bindings[parentKey]) {
1553 | // this is a nested value binding, but the binding for its parent
1554 | // has not been created yet. We better create that one too.
1555 | compiler.createBinding(parentKey)
1556 | }
1557 | }
1558 | }
1559 | return binding
1560 | }
1561 |
1562 | /**
1563 | * Define the getter/setter for a root-level property on the VM
1564 | * and observe the initial value
1565 | */
1566 | CompilerProto.defineProp = function (key, binding) {
1567 | var compiler = this,
1568 | data = compiler.data,
1569 | ob = data.__emitter__
1570 |
1571 | // make sure the key is present in data
1572 | // so it can be observed
1573 | if (!(hasOwn.call(data, key))) {
1574 | data[key] = undefined
1575 | }
1576 |
1577 | // if the data object is already observed, but the key
1578 | // is not observed, we need to add it to the observed keys.
1579 | if (ob && !(hasOwn.call(ob.values, key))) {
1580 | Observer.convertKey(data, key)
1581 | }
1582 |
1583 | binding.value = data[key]
1584 |
1585 | def(compiler.vm, key, {
1586 | get: function () {
1587 | return compiler.data[key]
1588 | },
1589 | set: function (val) {
1590 | compiler.data[key] = val
1591 | }
1592 | })
1593 | }
1594 |
1595 | /**
1596 | * Define a meta property, e.g. $index or $key,
1597 | * which is bindable but only accessible on the VM,
1598 | * not in the data.
1599 | */
1600 | CompilerProto.defineMeta = function (key, binding) {
1601 | var ob = this.observer
1602 | binding.value = this.data[key]
1603 | delete this.data[key]
1604 | def(this.vm, key, {
1605 | get: function () {
1606 | if (Observer.shouldGet) ob.emit('get', key)
1607 | return binding.value
1608 | },
1609 | set: function (val) {
1610 | ob.emit('set', key, val)
1611 | }
1612 | })
1613 | }
1614 |
1615 | /**
1616 | * Define an expression binding, which is essentially
1617 | * an anonymous computed property
1618 | */
1619 | CompilerProto.defineExp = function (key, binding, directive) {
1620 | var computedKey = directive && directive.computedKey,
1621 | exp = computedKey ? directive.expression : key,
1622 | getter = this.expCache[exp]
1623 | if (!getter) {
1624 | getter = this.expCache[exp] = ExpParser.parse(computedKey || key, this)
1625 | }
1626 | if (getter) {
1627 | this.markComputed(binding, getter)
1628 | }
1629 | }
1630 |
1631 | /**
1632 | * Define a computed property on the VM
1633 | */
1634 | CompilerProto.defineComputed = function (key, binding, value) {
1635 | this.markComputed(binding, value)
1636 | def(this.vm, key, {
1637 | get: binding.value.$get,
1638 | set: binding.value.$set
1639 | })
1640 | }
1641 |
1642 | /**
1643 | * Process a computed property binding
1644 | * so its getter/setter are bound to proper context
1645 | */
1646 | CompilerProto.markComputed = function (binding, value) {
1647 | binding.isComputed = true
1648 | // bind the accessors to the vm
1649 | if (binding.isFn) {
1650 | binding.value = value
1651 | } else {
1652 | if (typeof value === 'function') {
1653 | value = { $get: value }
1654 | }
1655 | binding.value = {
1656 | $get: utils.bind(value.$get, this.vm),
1657 | $set: value.$set
1658 | ? utils.bind(value.$set, this.vm)
1659 | : undefined
1660 | }
1661 | }
1662 | // keep track for dep parsing later
1663 | this.computed.push(binding)
1664 | }
1665 |
1666 | /**
1667 | * Retrive an option from the compiler
1668 | */
1669 | CompilerProto.getOption = function (type, id, silent) {
1670 | var opts = this.options,
1671 | parent = this.parent,
1672 | globalAssets = config.globalAssets,
1673 | res = (opts[type] && opts[type][id]) || (
1674 | parent
1675 | ? parent.getOption(type, id, silent)
1676 | : globalAssets[type] && globalAssets[type][id]
1677 | )
1678 | if (!res && !silent && typeof id === 'string') {
1679 | utils.warn('Unknown ' + type.slice(0, -1) + ': ' + id)
1680 | }
1681 | return res
1682 | }
1683 |
1684 | /**
1685 | * Emit lifecycle events to trigger hooks
1686 | */
1687 | CompilerProto.execHook = function (event) {
1688 | event = 'hook:' + event
1689 | this.observer.emit(event)
1690 | this.emitter.emit(event)
1691 | }
1692 |
1693 | /**
1694 | * Check if a compiler's data contains a keypath
1695 | */
1696 | CompilerProto.hasKey = function (key) {
1697 | var baseKey = utils.baseKey(key)
1698 | return hasOwn.call(this.data, baseKey) ||
1699 | hasOwn.call(this.vm, baseKey)
1700 | }
1701 |
1702 | /**
1703 | * Do a one-time eval of a string that potentially
1704 | * includes bindings. It accepts additional raw data
1705 | * because we need to dynamically resolve v-component
1706 | * before a childVM is even compiled...
1707 | */
1708 | CompilerProto.eval = function (exp, data) {
1709 | var parsed = TextParser.parseAttr(exp)
1710 | return parsed
1711 | ? ExpParser.eval(parsed, this, data)
1712 | : exp
1713 | }
1714 |
1715 | /**
1716 | * Resolve a Component constructor for an element
1717 | * with the data to be used
1718 | */
1719 | CompilerProto.resolveComponent = function (node, data, test) {
1720 |
1721 | // late require to avoid circular deps
1722 | ViewModel = ViewModel || require('./viewmodel')
1723 |
1724 | var exp = utils.attr(node, 'component'),
1725 | tagName = node.tagName,
1726 | id = this.eval(exp, data),
1727 | tagId = (tagName.indexOf('-') > 0 && tagName.toLowerCase()),
1728 | Ctor = this.getOption('components', id || tagId, true)
1729 |
1730 | if (id && !Ctor) {
1731 | utils.warn('Unknown component: ' + id)
1732 | }
1733 |
1734 | return test
1735 | ? exp === ''
1736 | ? ViewModel
1737 | : Ctor
1738 | : Ctor || ViewModel
1739 | }
1740 |
1741 | /**
1742 | * Unbind and remove element
1743 | */
1744 | CompilerProto.destroy = function () {
1745 |
1746 | // avoid being called more than once
1747 | // this is irreversible!
1748 | if (this.destroyed) return
1749 |
1750 | var compiler = this,
1751 | i, j, key, dir, dirs, binding,
1752 | vm = compiler.vm,
1753 | el = compiler.el,
1754 | directives = compiler.dirs,
1755 | computed = compiler.computed,
1756 | bindings = compiler.bindings,
1757 | children = compiler.children,
1758 | parent = compiler.parent
1759 |
1760 | compiler.execHook('beforeDestroy')
1761 |
1762 | // unobserve data
1763 | Observer.unobserve(compiler.data, '', compiler.observer)
1764 |
1765 | // unbind all direcitves
1766 | i = directives.length
1767 | while (i--) {
1768 | dir = directives[i]
1769 | // if this directive is an instance of an external binding
1770 | // e.g. a directive that refers to a variable on the parent VM
1771 | // we need to remove it from that binding's directives
1772 | // * empty and literal bindings do not have binding.
1773 | if (dir.binding && dir.binding.compiler !== compiler) {
1774 | dirs = dir.binding.dirs
1775 | if (dirs) {
1776 | j = dirs.indexOf(dir)
1777 | if (j > -1) dirs.splice(j, 1)
1778 | }
1779 | }
1780 | dir.unbind()
1781 | }
1782 |
1783 | // unbind all computed, anonymous bindings
1784 | i = computed.length
1785 | while (i--) {
1786 | computed[i].unbind()
1787 | }
1788 |
1789 | // unbind all keypath bindings
1790 | for (key in bindings) {
1791 | binding = bindings[key]
1792 | if (binding) {
1793 | binding.unbind()
1794 | }
1795 | }
1796 |
1797 | // destroy all children
1798 | i = children.length
1799 | while (i--) {
1800 | children[i].destroy()
1801 | }
1802 |
1803 | // remove self from parent
1804 | if (parent) {
1805 | j = parent.children.indexOf(compiler)
1806 | if (j > -1) parent.children.splice(j, 1)
1807 | }
1808 |
1809 | // finally remove dom element
1810 | if (el === document.body) {
1811 | el.innerHTML = ''
1812 | } else {
1813 | vm.$remove()
1814 | }
1815 | el.vue_vm = null
1816 |
1817 | compiler.destroyed = true
1818 | // emit destroy hook
1819 | compiler.execHook('afterDestroy')
1820 |
1821 | // finally, unregister all listeners
1822 | compiler.observer.off()
1823 | compiler.emitter.off()
1824 | }
1825 |
1826 | // Helpers --------------------------------------------------------------------
1827 |
1828 | /**
1829 | * shorthand for getting root compiler
1830 | */
1831 | function getRoot (compiler) {
1832 | while (compiler.parent) {
1833 | compiler = compiler.parent
1834 | }
1835 | return compiler
1836 | }
1837 |
1838 | module.exports = Compiler
1839 | });
1840 | require.register("vue/src/viewmodel.js", function(exports, require, module){
1841 | var Compiler = require('./compiler'),
1842 | utils = require('./utils'),
1843 | transition = require('./transition'),
1844 | Batcher = require('./batcher'),
1845 | slice = [].slice,
1846 | def = utils.defProtected,
1847 | nextTick = utils.nextTick,
1848 |
1849 | // batch $watch callbacks
1850 | watcherBatcher = new Batcher(),
1851 | watcherId = 1
1852 |
1853 | /**
1854 | * ViewModel exposed to the user that holds data,
1855 | * computed properties, event handlers
1856 | * and a few reserved methods
1857 | */
1858 | function ViewModel (options) {
1859 | // just compile. options are passed directly to compiler
1860 | new Compiler(this, options)
1861 | }
1862 |
1863 | // All VM prototype methods are inenumerable
1864 | // so it can be stringified/looped through as raw data
1865 | var VMProto = ViewModel.prototype
1866 |
1867 | /**
1868 | * Convenience function to get a value from
1869 | * a keypath
1870 | */
1871 | def(VMProto, '$get', function (key) {
1872 | var val = utils.get(this, key)
1873 | return val === undefined && this.$parent
1874 | ? this.$parent.$get(key)
1875 | : val
1876 | })
1877 |
1878 | /**
1879 | * Convenience function to set an actual nested value
1880 | * from a flat key string. Used in directives.
1881 | */
1882 | def(VMProto, '$set', function (key, value) {
1883 | utils.set(this, key, value)
1884 | })
1885 |
1886 | /**
1887 | * watch a key on the viewmodel for changes
1888 | * fire callback with new value
1889 | */
1890 | def(VMProto, '$watch', function (key, callback) {
1891 | // save a unique id for each watcher
1892 | var id = watcherId++,
1893 | self = this
1894 | function on () {
1895 | var args = slice.call(arguments)
1896 | watcherBatcher.push({
1897 | id: id,
1898 | override: true,
1899 | execute: function () {
1900 | callback.apply(self, args)
1901 | }
1902 | })
1903 | }
1904 | callback._fn = on
1905 | self.$compiler.observer.on('change:' + key, on)
1906 | })
1907 |
1908 | /**
1909 | * unwatch a key
1910 | */
1911 | def(VMProto, '$unwatch', function (key, callback) {
1912 | // workaround here
1913 | // since the emitter module checks callback existence
1914 | // by checking the length of arguments
1915 | var args = ['change:' + key],
1916 | ob = this.$compiler.observer
1917 | if (callback) args.push(callback._fn)
1918 | ob.off.apply(ob, args)
1919 | })
1920 |
1921 | /**
1922 | * unbind everything, remove everything
1923 | */
1924 | def(VMProto, '$destroy', function () {
1925 | this.$compiler.destroy()
1926 | })
1927 |
1928 | /**
1929 | * broadcast an event to all child VMs recursively.
1930 | */
1931 | def(VMProto, '$broadcast', function () {
1932 | var children = this.$compiler.children,
1933 | i = children.length,
1934 | child
1935 | while (i--) {
1936 | child = children[i]
1937 | child.emitter.emit.apply(child.emitter, arguments)
1938 | child.vm.$broadcast.apply(child.vm, arguments)
1939 | }
1940 | })
1941 |
1942 | /**
1943 | * emit an event that propagates all the way up to parent VMs.
1944 | */
1945 | def(VMProto, '$dispatch', function () {
1946 | var compiler = this.$compiler,
1947 | emitter = compiler.emitter,
1948 | parent = compiler.parent
1949 | emitter.emit.apply(emitter, arguments)
1950 | if (parent) {
1951 | parent.vm.$dispatch.apply(parent.vm, arguments)
1952 | }
1953 | })
1954 |
1955 | /**
1956 | * delegate on/off/once to the compiler's emitter
1957 | */
1958 | ;['emit', 'on', 'off', 'once'].forEach(function (method) {
1959 | def(VMProto, '$' + method, function () {
1960 | var emitter = this.$compiler.emitter
1961 | emitter[method].apply(emitter, arguments)
1962 | })
1963 | })
1964 |
1965 | // DOM convenience methods
1966 |
1967 | def(VMProto, '$appendTo', function (target, cb) {
1968 | target = query(target)
1969 | var el = this.$el
1970 | transition(el, 1, function () {
1971 | target.appendChild(el)
1972 | if (cb) nextTick(cb)
1973 | }, this.$compiler)
1974 | })
1975 |
1976 | def(VMProto, '$remove', function (cb) {
1977 | var el = this.$el
1978 | transition(el, -1, function () {
1979 | if (el.parentNode) {
1980 | el.parentNode.removeChild(el)
1981 | }
1982 | if (cb) nextTick(cb)
1983 | }, this.$compiler)
1984 | })
1985 |
1986 | def(VMProto, '$before', function (target, cb) {
1987 | target = query(target)
1988 | var el = this.$el
1989 | transition(el, 1, function () {
1990 | target.parentNode.insertBefore(el, target)
1991 | if (cb) nextTick(cb)
1992 | }, this.$compiler)
1993 | })
1994 |
1995 | def(VMProto, '$after', function (target, cb) {
1996 | target = query(target)
1997 | var el = this.$el
1998 | transition(el, 1, function () {
1999 | if (target.nextSibling) {
2000 | target.parentNode.insertBefore(el, target.nextSibling)
2001 | } else {
2002 | target.parentNode.appendChild(el)
2003 | }
2004 | if (cb) nextTick(cb)
2005 | }, this.$compiler)
2006 | })
2007 |
2008 | function query (el) {
2009 | return typeof el === 'string'
2010 | ? document.querySelector(el)
2011 | : el
2012 | }
2013 |
2014 | module.exports = ViewModel
2015 | });
2016 | require.register("vue/src/binding.js", function(exports, require, module){
2017 | var Batcher = require('./batcher'),
2018 | bindingBatcher = new Batcher(),
2019 | bindingId = 1
2020 |
2021 | /**
2022 | * Binding class.
2023 | *
2024 | * each property on the viewmodel has one corresponding Binding object
2025 | * which has multiple directive instances on the DOM
2026 | * and multiple computed property dependents
2027 | */
2028 | function Binding (compiler, key, isExp, isFn) {
2029 | this.id = bindingId++
2030 | this.value = undefined
2031 | this.isExp = !!isExp
2032 | this.isFn = isFn
2033 | this.root = !this.isExp && key.indexOf('.') === -1
2034 | this.compiler = compiler
2035 | this.key = key
2036 | this.dirs = []
2037 | this.subs = []
2038 | this.deps = []
2039 | this.unbound = false
2040 | }
2041 |
2042 | var BindingProto = Binding.prototype
2043 |
2044 | /**
2045 | * Update value and queue instance updates.
2046 | */
2047 | BindingProto.update = function (value) {
2048 | if (!this.isComputed || this.isFn) {
2049 | this.value = value
2050 | }
2051 | if (this.dirs.length || this.subs.length) {
2052 | var self = this
2053 | bindingBatcher.push({
2054 | id: this.id,
2055 | execute: function () {
2056 | if (!self.unbound) {
2057 | self._update()
2058 | }
2059 | }
2060 | })
2061 | }
2062 | }
2063 |
2064 | /**
2065 | * Actually update the directives.
2066 | */
2067 | BindingProto._update = function () {
2068 | var i = this.dirs.length,
2069 | value = this.val()
2070 | while (i--) {
2071 | this.dirs[i].update(value)
2072 | }
2073 | this.pub()
2074 | }
2075 |
2076 | /**
2077 | * Return the valuated value regardless
2078 | * of whether it is computed or not
2079 | */
2080 | BindingProto.val = function () {
2081 | return this.isComputed && !this.isFn
2082 | ? this.value.$get()
2083 | : this.value
2084 | }
2085 |
2086 | /**
2087 | * Notify computed properties that depend on this binding
2088 | * to update themselves
2089 | */
2090 | BindingProto.pub = function () {
2091 | var i = this.subs.length
2092 | while (i--) {
2093 | this.subs[i].update()
2094 | }
2095 | }
2096 |
2097 | /**
2098 | * Unbind the binding, remove itself from all of its dependencies
2099 | */
2100 | BindingProto.unbind = function () {
2101 | // Indicate this has been unbound.
2102 | // It's possible this binding will be in
2103 | // the batcher's flush queue when its owner
2104 | // compiler has already been destroyed.
2105 | this.unbound = true
2106 | var i = this.dirs.length
2107 | while (i--) {
2108 | this.dirs[i].unbind()
2109 | }
2110 | i = this.deps.length
2111 | var subs
2112 | while (i--) {
2113 | subs = this.deps[i].subs
2114 | var j = subs.indexOf(this)
2115 | if (j > -1) subs.splice(j, 1)
2116 | }
2117 | }
2118 |
2119 | module.exports = Binding
2120 | });
2121 | require.register("vue/src/observer.js", function(exports, require, module){
2122 | /* jshint proto:true */
2123 |
2124 | var Emitter = require('./emitter'),
2125 | utils = require('./utils'),
2126 | // cache methods
2127 | def = utils.defProtected,
2128 | isObject = utils.isObject,
2129 | isArray = Array.isArray,
2130 | hasOwn = ({}).hasOwnProperty,
2131 | oDef = Object.defineProperty,
2132 | slice = [].slice,
2133 | // fix for IE + __proto__ problem
2134 | // define methods as inenumerable if __proto__ is present,
2135 | // otherwise enumerable so we can loop through and manually
2136 | // attach to array instances
2137 | hasProto = ({}).__proto__
2138 |
2139 | // Array Mutation Handlers & Augmentations ------------------------------------
2140 |
2141 | // The proxy prototype to replace the __proto__ of
2142 | // an observed array
2143 | var ArrayProxy = Object.create(Array.prototype)
2144 |
2145 | // intercept mutation methods
2146 | ;[
2147 | 'push',
2148 | 'pop',
2149 | 'shift',
2150 | 'unshift',
2151 | 'splice',
2152 | 'sort',
2153 | 'reverse'
2154 | ].forEach(watchMutation)
2155 |
2156 | // Augment the ArrayProxy with convenience methods
2157 | def(ArrayProxy, '$set', function (index, data) {
2158 | return this.splice(index, 1, data)[0]
2159 | }, !hasProto)
2160 |
2161 | def(ArrayProxy, '$remove', function (index) {
2162 | if (typeof index !== 'number') {
2163 | index = this.indexOf(index)
2164 | }
2165 | if (index > -1) {
2166 | return this.splice(index, 1)[0]
2167 | }
2168 | }, !hasProto)
2169 |
2170 | /**
2171 | * Intercep a mutation event so we can emit the mutation info.
2172 | * we also analyze what elements are added/removed and link/unlink
2173 | * them with the parent Array.
2174 | */
2175 | function watchMutation (method) {
2176 | def(ArrayProxy, method, function () {
2177 |
2178 | var args = slice.call(arguments),
2179 | result = Array.prototype[method].apply(this, args),
2180 | inserted, removed
2181 |
2182 | // determine new / removed elements
2183 | if (method === 'push' || method === 'unshift') {
2184 | inserted = args
2185 | } else if (method === 'pop' || method === 'shift') {
2186 | removed = [result]
2187 | } else if (method === 'splice') {
2188 | inserted = args.slice(2)
2189 | removed = result
2190 | }
2191 |
2192 | // link & unlink
2193 | linkArrayElements(this, inserted)
2194 | unlinkArrayElements(this, removed)
2195 |
2196 | // emit the mutation event
2197 | this.__emitter__.emit('mutate', '', this, {
2198 | method : method,
2199 | args : args,
2200 | result : result,
2201 | inserted : inserted,
2202 | removed : removed
2203 | })
2204 |
2205 | return result
2206 |
2207 | }, !hasProto)
2208 | }
2209 |
2210 | /**
2211 | * Link new elements to an Array, so when they change
2212 | * and emit events, the owner Array can be notified.
2213 | */
2214 | function linkArrayElements (arr, items) {
2215 | if (items) {
2216 | var i = items.length, item, owners
2217 | while (i--) {
2218 | item = items[i]
2219 | if (isWatchable(item)) {
2220 | // if object is not converted for observing
2221 | // convert it...
2222 | if (!item.__emitter__) {
2223 | convert(item)
2224 | watch(item)
2225 | }
2226 | owners = item.__emitter__.owners
2227 | if (owners.indexOf(arr) < 0) {
2228 | owners.push(arr)
2229 | }
2230 | }
2231 | }
2232 | }
2233 | }
2234 |
2235 | /**
2236 | * Unlink removed elements from the ex-owner Array.
2237 | */
2238 | function unlinkArrayElements (arr, items) {
2239 | if (items) {
2240 | var i = items.length, item
2241 | while (i--) {
2242 | item = items[i]
2243 | if (item && item.__emitter__) {
2244 | var owners = item.__emitter__.owners
2245 | if (owners) owners.splice(owners.indexOf(arr))
2246 | }
2247 | }
2248 | }
2249 | }
2250 |
2251 | // Object add/delete key augmentation -----------------------------------------
2252 |
2253 | var ObjProxy = Object.create(Object.prototype)
2254 |
2255 | def(ObjProxy, '$add', function (key, val) {
2256 | if (hasOwn.call(this, key)) return
2257 | this[key] = val
2258 | convertKey(this, key)
2259 | // emit a propagating set event
2260 | this.__emitter__.emit('set', key, val, true)
2261 | }, !hasProto)
2262 |
2263 | def(ObjProxy, '$delete', function (key) {
2264 | if (!(hasOwn.call(this, key))) return
2265 | // trigger set events
2266 | this[key] = undefined
2267 | delete this[key]
2268 | this.__emitter__.emit('delete', key)
2269 | }, !hasProto)
2270 |
2271 | // Watch Helpers --------------------------------------------------------------
2272 |
2273 | /**
2274 | * Check if a value is watchable
2275 | */
2276 | function isWatchable (obj) {
2277 | return typeof obj === 'object' && obj && !obj.$compiler
2278 | }
2279 |
2280 | /**
2281 | * Convert an Object/Array to give it a change emitter.
2282 | */
2283 | function convert (obj) {
2284 | if (obj.__emitter__) return true
2285 | var emitter = new Emitter()
2286 | def(obj, '__emitter__', emitter)
2287 | emitter
2288 | .on('set', function (key, val, propagate) {
2289 | if (propagate) propagateChange(obj)
2290 | })
2291 | .on('mutate', function () {
2292 | propagateChange(obj)
2293 | })
2294 | emitter.values = utils.hash()
2295 | emitter.owners = []
2296 | return false
2297 | }
2298 |
2299 | /**
2300 | * Propagate an array element's change to its owner arrays
2301 | */
2302 | function propagateChange (obj) {
2303 | var owners = obj.__emitter__.owners,
2304 | i = owners.length
2305 | while (i--) {
2306 | owners[i].__emitter__.emit('set', '', '', true)
2307 | }
2308 | }
2309 |
2310 | /**
2311 | * Watch target based on its type
2312 | */
2313 | function watch (obj) {
2314 | if (isArray(obj)) {
2315 | watchArray(obj)
2316 | } else {
2317 | watchObject(obj)
2318 | }
2319 | }
2320 |
2321 | /**
2322 | * Augment target objects with modified
2323 | * methods
2324 | */
2325 | function augment (target, src) {
2326 | if (hasProto) {
2327 | target.__proto__ = src
2328 | } else {
2329 | for (var key in src) {
2330 | def(target, key, src[key])
2331 | }
2332 | }
2333 | }
2334 |
2335 | /**
2336 | * Watch an Object, recursive.
2337 | */
2338 | function watchObject (obj) {
2339 | augment(obj, ObjProxy)
2340 | for (var key in obj) {
2341 | convertKey(obj, key)
2342 | }
2343 | }
2344 |
2345 | /**
2346 | * Watch an Array, overload mutation methods
2347 | * and add augmentations by intercepting the prototype chain
2348 | */
2349 | function watchArray (arr) {
2350 | augment(arr, ArrayProxy)
2351 | linkArrayElements(arr, arr)
2352 | }
2353 |
2354 | /**
2355 | * Define accessors for a property on an Object
2356 | * so it emits get/set events.
2357 | * Then watch the value itself.
2358 | */
2359 | function convertKey (obj, key) {
2360 | var keyPrefix = key.charAt(0)
2361 | if (keyPrefix === '$' || keyPrefix === '_') {
2362 | return
2363 | }
2364 | // emit set on bind
2365 | // this means when an object is observed it will emit
2366 | // a first batch of set events.
2367 | var emitter = obj.__emitter__,
2368 | values = emitter.values
2369 |
2370 | init(obj[key])
2371 |
2372 | oDef(obj, key, {
2373 | enumerable: true,
2374 | configurable: true,
2375 | get: function () {
2376 | var value = values[key]
2377 | // only emit get on tip values
2378 | if (pub.shouldGet) {
2379 | emitter.emit('get', key)
2380 | }
2381 | return value
2382 | },
2383 | set: function (newVal) {
2384 | var oldVal = values[key]
2385 | unobserve(oldVal, key, emitter)
2386 | copyPaths(newVal, oldVal)
2387 | // an immediate property should notify its parent
2388 | // to emit set for itself too
2389 | init(newVal, true)
2390 | }
2391 | })
2392 |
2393 | function init (val, propagate) {
2394 | values[key] = val
2395 | emitter.emit('set', key, val, propagate)
2396 | if (isArray(val)) {
2397 | emitter.emit('set', key + '.length', val.length, propagate)
2398 | }
2399 | observe(val, key, emitter)
2400 | }
2401 | }
2402 |
2403 | /**
2404 | * When a value that is already converted is
2405 | * observed again by another observer, we can skip
2406 | * the watch conversion and simply emit set event for
2407 | * all of its properties.
2408 | */
2409 | function emitSet (obj) {
2410 | var emitter = obj && obj.__emitter__
2411 | if (!emitter) return
2412 | if (isArray(obj)) {
2413 | emitter.emit('set', 'length', obj.length)
2414 | } else {
2415 | var key, val
2416 | for (key in obj) {
2417 | val = obj[key]
2418 | emitter.emit('set', key, val)
2419 | emitSet(val)
2420 | }
2421 | }
2422 | }
2423 |
2424 | /**
2425 | * Make sure all the paths in an old object exists
2426 | * in a new object.
2427 | * So when an object changes, all missing keys will
2428 | * emit a set event with undefined value.
2429 | */
2430 | function copyPaths (newObj, oldObj) {
2431 | if (!isObject(newObj) || !isObject(oldObj)) {
2432 | return
2433 | }
2434 | var path, oldVal, newVal
2435 | for (path in oldObj) {
2436 | if (!(hasOwn.call(newObj, path))) {
2437 | oldVal = oldObj[path]
2438 | if (isArray(oldVal)) {
2439 | newObj[path] = []
2440 | } else if (isObject(oldVal)) {
2441 | newVal = newObj[path] = {}
2442 | copyPaths(newVal, oldVal)
2443 | } else {
2444 | newObj[path] = undefined
2445 | }
2446 | }
2447 | }
2448 | }
2449 |
2450 | /**
2451 | * walk along a path and make sure it can be accessed
2452 | * and enumerated in that object
2453 | */
2454 | function ensurePath (obj, key) {
2455 | var path = key.split('.'), sec
2456 | for (var i = 0, d = path.length - 1; i < d; i++) {
2457 | sec = path[i]
2458 | if (!obj[sec]) {
2459 | obj[sec] = {}
2460 | if (obj.__emitter__) convertKey(obj, sec)
2461 | }
2462 | obj = obj[sec]
2463 | }
2464 | if (isObject(obj)) {
2465 | sec = path[i]
2466 | if (!(hasOwn.call(obj, sec))) {
2467 | obj[sec] = undefined
2468 | if (obj.__emitter__) convertKey(obj, sec)
2469 | }
2470 | }
2471 | }
2472 |
2473 | // Main API Methods -----------------------------------------------------------
2474 |
2475 | /**
2476 | * Observe an object with a given path,
2477 | * and proxy get/set/mutate events to the provided observer.
2478 | */
2479 | function observe (obj, rawPath, observer) {
2480 |
2481 | if (!isWatchable(obj)) return
2482 |
2483 | var path = rawPath ? rawPath + '.' : '',
2484 | alreadyConverted = convert(obj),
2485 | emitter = obj.__emitter__
2486 |
2487 | // setup proxy listeners on the parent observer.
2488 | // we need to keep reference to them so that they
2489 | // can be removed when the object is un-observed.
2490 | observer.proxies = observer.proxies || {}
2491 | var proxies = observer.proxies[path] = {
2492 | get: function (key) {
2493 | observer.emit('get', path + key)
2494 | },
2495 | set: function (key, val, propagate) {
2496 | if (key) observer.emit('set', path + key, val)
2497 | // also notify observer that the object itself changed
2498 | // but only do so when it's a immediate property. this
2499 | // avoids duplicate event firing.
2500 | if (rawPath && propagate) {
2501 | observer.emit('set', rawPath, obj, true)
2502 | }
2503 | },
2504 | mutate: function (key, val, mutation) {
2505 | // if the Array is a root value
2506 | // the key will be null
2507 | var fixedPath = key ? path + key : rawPath
2508 | observer.emit('mutate', fixedPath, val, mutation)
2509 | // also emit set for Array's length when it mutates
2510 | var m = mutation.method
2511 | if (m !== 'sort' && m !== 'reverse') {
2512 | observer.emit('set', fixedPath + '.length', val.length)
2513 | }
2514 | }
2515 | }
2516 |
2517 | // attach the listeners to the child observer.
2518 | // now all the events will propagate upwards.
2519 | emitter
2520 | .on('get', proxies.get)
2521 | .on('set', proxies.set)
2522 | .on('mutate', proxies.mutate)
2523 |
2524 | if (alreadyConverted) {
2525 | // for objects that have already been converted,
2526 | // emit set events for everything inside
2527 | emitSet(obj)
2528 | } else {
2529 | watch(obj)
2530 | }
2531 | }
2532 |
2533 | /**
2534 | * Cancel observation, turn off the listeners.
2535 | */
2536 | function unobserve (obj, path, observer) {
2537 |
2538 | if (!obj || !obj.__emitter__) return
2539 |
2540 | path = path ? path + '.' : ''
2541 | var proxies = observer.proxies[path]
2542 | if (!proxies) return
2543 |
2544 | // turn off listeners
2545 | obj.__emitter__
2546 | .off('get', proxies.get)
2547 | .off('set', proxies.set)
2548 | .off('mutate', proxies.mutate)
2549 |
2550 | // remove reference
2551 | observer.proxies[path] = null
2552 | }
2553 |
2554 | // Expose API -----------------------------------------------------------------
2555 |
2556 | var pub = module.exports = {
2557 |
2558 | // whether to emit get events
2559 | // only enabled during dependency parsing
2560 | shouldGet : false,
2561 |
2562 | observe : observe,
2563 | unobserve : unobserve,
2564 | ensurePath : ensurePath,
2565 | copyPaths : copyPaths,
2566 | watch : watch,
2567 | convert : convert,
2568 | convertKey : convertKey
2569 | }
2570 | });
2571 | require.register("vue/src/directive.js", function(exports, require, module){
2572 | var dirId = 1,
2573 | ARG_RE = /^[\w\$-]+$/,
2574 | FILTER_TOKEN_RE = /[^\s'"]+|'[^']+'|"[^"]+"/g,
2575 | NESTING_RE = /^\$(parent|root)\./,
2576 | SINGLE_VAR_RE = /^[\w\.$]+$/,
2577 | QUOTE_RE = /"/g
2578 |
2579 | /**
2580 | * Directive class
2581 | * represents a single directive instance in the DOM
2582 | */
2583 | function Directive (name, ast, definition, compiler, el) {
2584 |
2585 | this.id = dirId++
2586 | this.name = name
2587 | this.compiler = compiler
2588 | this.vm = compiler.vm
2589 | this.el = el
2590 | this.computeFilters = false
2591 | this.key = ast.key
2592 | this.arg = ast.arg
2593 | this.expression = ast.expression
2594 |
2595 | var isEmpty = this.expression === ''
2596 |
2597 | // mix in properties from the directive definition
2598 | if (typeof definition === 'function') {
2599 | this[isEmpty ? 'bind' : '_update'] = definition
2600 | } else {
2601 | for (var prop in definition) {
2602 | if (prop === 'unbind' || prop === 'update') {
2603 | this['_' + prop] = definition[prop]
2604 | } else {
2605 | this[prop] = definition[prop]
2606 | }
2607 | }
2608 | }
2609 |
2610 | // empty expression, we're done.
2611 | if (isEmpty || this.isEmpty) {
2612 | this.isEmpty = true
2613 | return
2614 | }
2615 |
2616 | this.expression = (
2617 | this.isLiteral
2618 | ? compiler.eval(this.expression)
2619 | : this.expression
2620 | ).trim()
2621 |
2622 | var filters = ast.filters,
2623 | filter, fn, i, l, computed
2624 | if (filters) {
2625 | this.filters = []
2626 | for (i = 0, l = filters.length; i < l; i++) {
2627 | filter = filters[i]
2628 | fn = this.compiler.getOption('filters', filter.name)
2629 | if (fn) {
2630 | filter.apply = fn
2631 | this.filters.push(filter)
2632 | if (fn.computed) {
2633 | computed = true
2634 | }
2635 | }
2636 | }
2637 | }
2638 |
2639 | if (!this.filters || !this.filters.length) {
2640 | this.filters = null
2641 | }
2642 |
2643 | if (computed) {
2644 | this.computedKey = Directive.inlineFilters(this.key, this.filters)
2645 | this.filters = null
2646 | }
2647 |
2648 | this.isExp =
2649 | computed ||
2650 | !SINGLE_VAR_RE.test(this.key) ||
2651 | NESTING_RE.test(this.key)
2652 |
2653 | }
2654 |
2655 | var DirProto = Directive.prototype
2656 |
2657 | /**
2658 | * called when a new value is set
2659 | * for computed properties, this will only be called once
2660 | * during initialization.
2661 | */
2662 | DirProto.update = function (value, init) {
2663 | if (init || value !== this.value || (value && typeof value === 'object')) {
2664 | this.value = value
2665 | if (this._update) {
2666 | this._update(
2667 | this.filters && !this.computeFilters
2668 | ? this.applyFilters(value)
2669 | : value,
2670 | init
2671 | )
2672 | }
2673 | }
2674 | }
2675 |
2676 | /**
2677 | * pipe the value through filters
2678 | */
2679 | DirProto.applyFilters = function (value) {
2680 | var filtered = value, filter
2681 | for (var i = 0, l = this.filters.length; i < l; i++) {
2682 | filter = this.filters[i]
2683 | filtered = filter.apply.apply(this.vm, [filtered].concat(filter.args))
2684 | }
2685 | return filtered
2686 | }
2687 |
2688 | /**
2689 | * Unbind diretive
2690 | */
2691 | DirProto.unbind = function () {
2692 | // this can be called before the el is even assigned...
2693 | if (!this.el || !this.vm) return
2694 | if (this._unbind) this._unbind()
2695 | this.vm = this.el = this.binding = this.compiler = null
2696 | }
2697 |
2698 | // Exposed static methods -----------------------------------------------------
2699 |
2700 | /**
2701 | * Parse a directive string into an Array of
2702 | * AST-like objects representing directives
2703 | */
2704 | Directive.parse = function (str) {
2705 |
2706 | var inSingle = false,
2707 | inDouble = false,
2708 | curly = 0,
2709 | square = 0,
2710 | paren = 0,
2711 | begin = 0,
2712 | argIndex = 0,
2713 | dirs = [],
2714 | dir = {},
2715 | lastFilterIndex = 0,
2716 | arg
2717 |
2718 | for (var c, i = 0, l = str.length; i < l; i++) {
2719 | c = str.charAt(i)
2720 | if (inSingle) {
2721 | // check single quote
2722 | if (c === "'") inSingle = !inSingle
2723 | } else if (inDouble) {
2724 | // check double quote
2725 | if (c === '"') inDouble = !inDouble
2726 | } else if (c === ',' && !paren && !curly && !square) {
2727 | // reached the end of a directive
2728 | pushDir()
2729 | // reset & skip the comma
2730 | dir = {}
2731 | begin = argIndex = lastFilterIndex = i + 1
2732 | } else if (c === ':' && !dir.key && !dir.arg) {
2733 | // argument
2734 | arg = str.slice(begin, i).trim()
2735 | if (ARG_RE.test(arg)) {
2736 | argIndex = i + 1
2737 | dir.arg = str.slice(begin, i).trim()
2738 | }
2739 | } else if (c === '|' && str.charAt(i + 1) !== '|' && str.charAt(i - 1) !== '|') {
2740 | if (dir.key === undefined) {
2741 | // first filter, end of key
2742 | lastFilterIndex = i + 1
2743 | dir.key = str.slice(argIndex, i).trim()
2744 | } else {
2745 | // already has filter
2746 | pushFilter()
2747 | }
2748 | } else if (c === '"') {
2749 | inDouble = true
2750 | } else if (c === "'") {
2751 | inSingle = true
2752 | } else if (c === '(') {
2753 | paren++
2754 | } else if (c === ')') {
2755 | paren--
2756 | } else if (c === '[') {
2757 | square++
2758 | } else if (c === ']') {
2759 | square--
2760 | } else if (c === '{') {
2761 | curly++
2762 | } else if (c === '}') {
2763 | curly--
2764 | }
2765 | }
2766 | if (i === 0 || begin !== i) {
2767 | pushDir()
2768 | }
2769 |
2770 | function pushDir () {
2771 | dir.expression = str.slice(begin, i).trim()
2772 | if (dir.key === undefined) {
2773 | dir.key = str.slice(argIndex, i).trim()
2774 | } else if (lastFilterIndex !== begin) {
2775 | pushFilter()
2776 | }
2777 | if (i === 0 || dir.key) {
2778 | dirs.push(dir)
2779 | }
2780 | }
2781 |
2782 | function pushFilter () {
2783 | var exp = str.slice(lastFilterIndex, i).trim(),
2784 | filter
2785 | if (exp) {
2786 | filter = {}
2787 | var tokens = exp.match(FILTER_TOKEN_RE)
2788 | filter.name = tokens[0]
2789 | filter.args = tokens.length > 1 ? tokens.slice(1) : null
2790 | }
2791 | if (filter) {
2792 | (dir.filters = dir.filters || []).push(filter)
2793 | }
2794 | lastFilterIndex = i + 1
2795 | }
2796 |
2797 | return dirs
2798 | }
2799 |
2800 | /**
2801 | * Inline computed filters so they become part
2802 | * of the expression
2803 | */
2804 | Directive.inlineFilters = function (key, filters) {
2805 | var args, filter
2806 | for (var i = 0, l = filters.length; i < l; i++) {
2807 | filter = filters[i]
2808 | args = filter.args
2809 | ? ',"' + filter.args.map(escapeQuote).join('","') + '"'
2810 | : ''
2811 | key = 'this.$compiler.getOption("filters", "' +
2812 | filter.name +
2813 | '").call(this,' +
2814 | key + args +
2815 | ')'
2816 | }
2817 | return key
2818 | }
2819 |
2820 | /**
2821 | * Convert double quotes to single quotes
2822 | * so they don't mess up the generated function body
2823 | */
2824 | function escapeQuote (v) {
2825 | return v.indexOf('"') > -1
2826 | ? v.replace(QUOTE_RE, '\'')
2827 | : v
2828 | }
2829 |
2830 | module.exports = Directive
2831 | });
2832 | require.register("vue/src/exp-parser.js", function(exports, require, module){
2833 | var utils = require('./utils'),
2834 | STR_SAVE_RE = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
2835 | STR_RESTORE_RE = /"(\d+)"/g,
2836 | NEWLINE_RE = /\n/g,
2837 | CTOR_RE = new RegExp('constructor'.split('').join('[\'"+, ]*')),
2838 | UNICODE_RE = /\\u\d\d\d\d/
2839 |
2840 | // Variable extraction scooped from https://github.com/RubyLouvre/avalon
2841 |
2842 | var KEYWORDS =
2843 | // keywords
2844 | 'break,case,catch,continue,debugger,default,delete,do,else,false' +
2845 | ',finally,for,function,if,in,instanceof,new,null,return,switch,this' +
2846 | ',throw,true,try,typeof,var,void,while,with,undefined' +
2847 | // reserved
2848 | ',abstract,boolean,byte,char,class,const,double,enum,export,extends' +
2849 | ',final,float,goto,implements,import,int,interface,long,native' +
2850 | ',package,private,protected,public,short,static,super,synchronized' +
2851 | ',throws,transient,volatile' +
2852 | // ECMA 5 - use strict
2853 | ',arguments,let,yield' +
2854 | // allow using Math in expressions
2855 | ',Math',
2856 |
2857 | KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g'),
2858 | REMOVE_RE = /\/\*(?:.|\n)*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|'[^']*'|"[^"]*"|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g,
2859 | SPLIT_RE = /[^\w$]+/g,
2860 | NUMBER_RE = /\b\d[^,]*/g,
2861 | BOUNDARY_RE = /^,+|,+$/g
2862 |
2863 | /**
2864 | * Strip top level variable names from a snippet of JS expression
2865 | */
2866 | function getVariables (code) {
2867 | code = code
2868 | .replace(REMOVE_RE, '')
2869 | .replace(SPLIT_RE, ',')
2870 | .replace(KEYWORDS_RE, '')
2871 | .replace(NUMBER_RE, '')
2872 | .replace(BOUNDARY_RE, '')
2873 | return code
2874 | ? code.split(/,+/)
2875 | : []
2876 | }
2877 |
2878 | /**
2879 | * A given path could potentially exist not on the
2880 | * current compiler, but up in the parent chain somewhere.
2881 | * This function generates an access relationship string
2882 | * that can be used in the getter function by walking up
2883 | * the parent chain to check for key existence.
2884 | *
2885 | * It stops at top parent if no vm in the chain has the
2886 | * key. It then creates any missing bindings on the
2887 | * final resolved vm.
2888 | */
2889 | function traceScope (path, compiler, data) {
2890 | var rel = '',
2891 | dist = 0,
2892 | self = compiler
2893 |
2894 | if (data && utils.get(data, path) !== undefined) {
2895 | // hack: temporarily attached data
2896 | return '$temp.'
2897 | }
2898 |
2899 | while (compiler) {
2900 | if (compiler.hasKey(path)) {
2901 | break
2902 | } else {
2903 | compiler = compiler.parent
2904 | dist++
2905 | }
2906 | }
2907 | if (compiler) {
2908 | while (dist--) {
2909 | rel += '$parent.'
2910 | }
2911 | if (!compiler.bindings[path] && path.charAt(0) !== '$') {
2912 | compiler.createBinding(path)
2913 | }
2914 | } else {
2915 | self.createBinding(path)
2916 | }
2917 | return rel
2918 | }
2919 |
2920 | /**
2921 | * Create a function from a string...
2922 | * this looks like evil magic but since all variables are limited
2923 | * to the VM's data it's actually properly sandboxed
2924 | */
2925 | function makeGetter (exp, raw) {
2926 | var fn
2927 | try {
2928 | fn = new Function(exp)
2929 | } catch (e) {
2930 | utils.warn('Error parsing expression: ' + raw)
2931 | }
2932 | return fn
2933 | }
2934 |
2935 | /**
2936 | * Escape a leading dollar sign for regex construction
2937 | */
2938 | function escapeDollar (v) {
2939 | return v.charAt(0) === '$'
2940 | ? '\\' + v
2941 | : v
2942 | }
2943 |
2944 | /**
2945 | * Parse and return an anonymous computed property getter function
2946 | * from an arbitrary expression, together with a list of paths to be
2947 | * created as bindings.
2948 | */
2949 | exports.parse = function (exp, compiler, data) {
2950 | // unicode and 'constructor' are not allowed for XSS security.
2951 | if (UNICODE_RE.test(exp) || CTOR_RE.test(exp)) {
2952 | utils.warn('Unsafe expression: ' + exp)
2953 | return
2954 | }
2955 | // extract variable names
2956 | var vars = getVariables(exp)
2957 | if (!vars.length) {
2958 | return makeGetter('return ' + exp, exp)
2959 | }
2960 | vars = utils.unique(vars)
2961 |
2962 | var accessors = '',
2963 | has = utils.hash(),
2964 | strings = [],
2965 | // construct a regex to extract all valid variable paths
2966 | // ones that begin with "$" are particularly tricky
2967 | // because we can't use \b for them
2968 | pathRE = new RegExp(
2969 | "[^$\\w\\.](" +
2970 | vars.map(escapeDollar).join('|') +
2971 | ")[$\\w\\.]*\\b", 'g'
2972 | ),
2973 | body = (' ' + exp)
2974 | .replace(STR_SAVE_RE, saveStrings)
2975 | .replace(pathRE, replacePath)
2976 | .replace(STR_RESTORE_RE, restoreStrings)
2977 |
2978 | body = accessors + 'return ' + body
2979 |
2980 | function saveStrings (str) {
2981 | var i = strings.length
2982 | // escape newlines in strings so the expression
2983 | // can be correctly evaluated
2984 | strings[i] = str.replace(NEWLINE_RE, '\\n')
2985 | return '"' + i + '"'
2986 | }
2987 |
2988 | function replacePath (path) {
2989 | // keep track of the first char
2990 | var c = path.charAt(0)
2991 | path = path.slice(1)
2992 | var val = 'this.' + traceScope(path, compiler, data) + path
2993 | if (!has[path]) {
2994 | accessors += val + ';'
2995 | has[path] = 1
2996 | }
2997 | // don't forget to put that first char back
2998 | return c + val
2999 | }
3000 |
3001 | function restoreStrings (str, i) {
3002 | return strings[i]
3003 | }
3004 |
3005 | return makeGetter(body, exp)
3006 | }
3007 |
3008 | /**
3009 | * Evaluate an expression in the context of a compiler.
3010 | * Accepts additional data.
3011 | */
3012 | exports.eval = function (exp, compiler, data) {
3013 | var getter = exports.parse(exp, compiler, data), res
3014 | if (getter) {
3015 | // hack: temporarily attach the additional data so
3016 | // it can be accessed in the getter
3017 | compiler.vm.$temp = data
3018 | res = getter.call(compiler.vm)
3019 | delete compiler.vm.$temp
3020 | }
3021 | return res
3022 | }
3023 | });
3024 | require.register("vue/src/text-parser.js", function(exports, require, module){
3025 | var openChar = '{',
3026 | endChar = '}',
3027 | ESCAPE_RE = /[-.*+?^${}()|[\]\/\\]/g,
3028 | BINDING_RE = buildInterpolationRegex(),
3029 | // lazy require
3030 | Directive
3031 |
3032 | function buildInterpolationRegex () {
3033 | var open = escapeRegex(openChar),
3034 | end = escapeRegex(endChar)
3035 | return new RegExp(open + open + open + '?(.+?)' + end + '?' + end + end)
3036 | }
3037 |
3038 | function escapeRegex (str) {
3039 | return str.replace(ESCAPE_RE, '\\$&')
3040 | }
3041 |
3042 | function setDelimiters (delimiters) {
3043 | exports.delimiters = delimiters
3044 | openChar = delimiters[0]
3045 | endChar = delimiters[1]
3046 | BINDING_RE = buildInterpolationRegex()
3047 | }
3048 |
3049 | /**
3050 | * Parse a piece of text, return an array of tokens
3051 | * token types:
3052 | * 1. plain string
3053 | * 2. object with key = binding key
3054 | * 3. object with key & html = true
3055 | */
3056 | function parse (text) {
3057 | if (!BINDING_RE.test(text)) return null
3058 | var m, i, token, match, tokens = []
3059 | /* jshint boss: true */
3060 | while (m = text.match(BINDING_RE)) {
3061 | i = m.index
3062 | if (i > 0) tokens.push(text.slice(0, i))
3063 | token = { key: m[1].trim() }
3064 | match = m[0]
3065 | token.html =
3066 | match.charAt(2) === openChar &&
3067 | match.charAt(match.length - 3) === endChar
3068 | tokens.push(token)
3069 | text = text.slice(i + m[0].length)
3070 | }
3071 | if (text.length) tokens.push(text)
3072 | return tokens
3073 | }
3074 |
3075 | /**
3076 | * Parse an attribute value with possible interpolation tags
3077 | * return a Directive-friendly expression
3078 | *
3079 | * e.g. a {{b}} c => "a " + b + " c"
3080 | */
3081 | function parseAttr (attr) {
3082 | Directive = Directive || require('./directive')
3083 | var tokens = parse(attr)
3084 | if (!tokens) return null
3085 | if (tokens.length === 1) return tokens[0].key
3086 | var res = [], token
3087 | for (var i = 0, l = tokens.length; i < l; i++) {
3088 | token = tokens[i]
3089 | res.push(
3090 | token.key
3091 | ? inlineFilters(token.key)
3092 | : ('"' + token + '"')
3093 | )
3094 | }
3095 | return res.join('+')
3096 | }
3097 |
3098 | /**
3099 | * Inlines any possible filters in a binding
3100 | * so that we can combine everything into a huge expression
3101 | */
3102 | function inlineFilters (key) {
3103 | if (key.indexOf('|') > -1) {
3104 | var dirs = Directive.parse(key),
3105 | dir = dirs && dirs[0]
3106 | if (dir && dir.filters) {
3107 | key = Directive.inlineFilters(
3108 | dir.key,
3109 | dir.filters
3110 | )
3111 | }
3112 | }
3113 | return '(' + key + ')'
3114 | }
3115 |
3116 | exports.parse = parse
3117 | exports.parseAttr = parseAttr
3118 | exports.setDelimiters = setDelimiters
3119 | exports.delimiters = [openChar, endChar]
3120 | });
3121 | require.register("vue/src/deps-parser.js", function(exports, require, module){
3122 | var Emitter = require('./emitter'),
3123 | utils = require('./utils'),
3124 | Observer = require('./observer'),
3125 | catcher = new Emitter()
3126 |
3127 | /**
3128 | * Auto-extract the dependencies of a computed property
3129 | * by recording the getters triggered when evaluating it.
3130 | */
3131 | function catchDeps (binding) {
3132 | if (binding.isFn) return
3133 | utils.log('\n- ' + binding.key)
3134 | var got = utils.hash()
3135 | binding.deps = []
3136 | catcher.on('get', function (dep) {
3137 | var has = got[dep.key]
3138 | if (
3139 | // avoid duplicate bindings
3140 | (has && has.compiler === dep.compiler) ||
3141 | // avoid repeated items as dependency
3142 | // only when the binding is from self or the parent chain
3143 | (dep.compiler.repeat && !isParentOf(dep.compiler, binding.compiler))
3144 | ) {
3145 | return
3146 | }
3147 | got[dep.key] = dep
3148 | utils.log(' - ' + dep.key)
3149 | binding.deps.push(dep)
3150 | dep.subs.push(binding)
3151 | })
3152 | binding.value.$get()
3153 | catcher.off('get')
3154 | }
3155 |
3156 | /**
3157 | * Test if A is a parent of or equals B
3158 | */
3159 | function isParentOf (a, b) {
3160 | while (b) {
3161 | if (a === b) {
3162 | return true
3163 | }
3164 | b = b.parent
3165 | }
3166 | }
3167 |
3168 | module.exports = {
3169 |
3170 | /**
3171 | * the observer that catches events triggered by getters
3172 | */
3173 | catcher: catcher,
3174 |
3175 | /**
3176 | * parse a list of computed property bindings
3177 | */
3178 | parse: function (bindings) {
3179 | utils.log('\nparsing dependencies...')
3180 | Observer.shouldGet = true
3181 | bindings.forEach(catchDeps)
3182 | Observer.shouldGet = false
3183 | utils.log('\ndone.')
3184 | }
3185 |
3186 | }
3187 | });
3188 | require.register("vue/src/filters.js", function(exports, require, module){
3189 | var utils = require('./utils'),
3190 | get = utils.get,
3191 | slice = [].slice,
3192 | QUOTE_RE = /^'.*'$/,
3193 | filters = module.exports = utils.hash()
3194 |
3195 | /**
3196 | * 'abc' => 'Abc'
3197 | */
3198 | filters.capitalize = function (value) {
3199 | if (!value && value !== 0) return ''
3200 | value = value.toString()
3201 | return value.charAt(0).toUpperCase() + value.slice(1)
3202 | }
3203 |
3204 | /**
3205 | * 'abc' => 'ABC'
3206 | */
3207 | filters.uppercase = function (value) {
3208 | return (value || value === 0)
3209 | ? value.toString().toUpperCase()
3210 | : ''
3211 | }
3212 |
3213 | /**
3214 | * 'AbC' => 'abc'
3215 | */
3216 | filters.lowercase = function (value) {
3217 | return (value || value === 0)
3218 | ? value.toString().toLowerCase()
3219 | : ''
3220 | }
3221 |
3222 | /**
3223 | * 12345 => $12,345.00
3224 | */
3225 | filters.currency = function (value, sign) {
3226 | if (!value && value !== 0) return ''
3227 | sign = sign || '$'
3228 | var s = Math.floor(value).toString(),
3229 | i = s.length % 3,
3230 | h = i > 0 ? (s.slice(0, i) + (s.length > 3 ? ',' : '')) : '',
3231 | f = '.' + value.toFixed(2).slice(-2)
3232 | return sign + h + s.slice(i).replace(/(\d{3})(?=\d)/g, '$1,') + f
3233 | }
3234 |
3235 | /**
3236 | * args: an array of strings corresponding to
3237 | * the single, double, triple ... forms of the word to
3238 | * be pluralized. When the number to be pluralized
3239 | * exceeds the length of the args, it will use the last
3240 | * entry in the array.
3241 | *
3242 | * e.g. ['single', 'double', 'triple', 'multiple']
3243 | */
3244 | filters.pluralize = function (value) {
3245 | var args = slice.call(arguments, 1)
3246 | return args.length > 1
3247 | ? (args[value - 1] || args[args.length - 1])
3248 | : (args[value - 1] || args[0] + 's')
3249 | }
3250 |
3251 | /**
3252 | * A special filter that takes a handler function,
3253 | * wraps it so it only gets triggered on specific keypresses.
3254 | *
3255 | * v-on only
3256 | */
3257 |
3258 | var keyCodes = {
3259 | enter : 13,
3260 | tab : 9,
3261 | 'delete' : 46,
3262 | up : 38,
3263 | left : 37,
3264 | right : 39,
3265 | down : 40,
3266 | esc : 27
3267 | }
3268 |
3269 | filters.key = function (handler, key) {
3270 | if (!handler) return
3271 | var code = keyCodes[key]
3272 | if (!code) {
3273 | code = parseInt(key, 10)
3274 | }
3275 | return function (e) {
3276 | if (e.keyCode === code) {
3277 | return handler.call(this, e)
3278 | }
3279 | }
3280 | }
3281 |
3282 | /**
3283 | * Filter filter for v-repeat
3284 | */
3285 | filters.filterBy = function (arr, searchKey, delimiter, dataKey) {
3286 |
3287 | // allow optional `in` delimiter
3288 | // because why not
3289 | if (delimiter && delimiter !== 'in') {
3290 | dataKey = delimiter
3291 | }
3292 |
3293 | // get the search string
3294 | var search = stripQuotes(searchKey) || this.$get(searchKey)
3295 | if (!search) return arr
3296 | search = search.toLowerCase()
3297 |
3298 | // get the optional dataKey
3299 | dataKey = dataKey && (stripQuotes(dataKey) || this.$get(dataKey))
3300 |
3301 | // convert object to array
3302 | if (!Array.isArray(arr)) {
3303 | arr = utils.objectToArray(arr)
3304 | }
3305 |
3306 | return arr.filter(function (item) {
3307 | return dataKey
3308 | ? contains(get(item, dataKey), search)
3309 | : contains(item, search)
3310 | })
3311 |
3312 | }
3313 |
3314 | filters.filterBy.computed = true
3315 |
3316 | /**
3317 | * Sort fitler for v-repeat
3318 | */
3319 | filters.orderBy = function (arr, sortKey, reverseKey) {
3320 |
3321 | var key = stripQuotes(sortKey) || this.$get(sortKey)
3322 | if (!key) return arr
3323 |
3324 | // convert object to array
3325 | if (!Array.isArray(arr)) {
3326 | arr = utils.objectToArray(arr)
3327 | }
3328 |
3329 | var order = 1
3330 | if (reverseKey) {
3331 | if (reverseKey === '-1') {
3332 | order = -1
3333 | } else if (reverseKey.charAt(0) === '!') {
3334 | reverseKey = reverseKey.slice(1)
3335 | order = this.$get(reverseKey) ? 1 : -1
3336 | } else {
3337 | order = this.$get(reverseKey) ? -1 : 1
3338 | }
3339 | }
3340 |
3341 | // sort on a copy to avoid mutating original array
3342 | return arr.slice().sort(function (a, b) {
3343 | a = get(a, key)
3344 | b = get(b, key)
3345 | return a === b ? 0 : a > b ? order : -order
3346 | })
3347 |
3348 | }
3349 |
3350 | filters.orderBy.computed = true
3351 |
3352 | // Array filter helpers -------------------------------------------------------
3353 |
3354 | /**
3355 | * String contain helper
3356 | */
3357 | function contains (val, search) {
3358 | /* jshint eqeqeq: false */
3359 | if (utils.isObject(val)) {
3360 | for (var key in val) {
3361 | if (contains(val[key], search)) {
3362 | return true
3363 | }
3364 | }
3365 | } else if (val != null) {
3366 | return val.toString().toLowerCase().indexOf(search) > -1
3367 | }
3368 | }
3369 |
3370 | /**
3371 | * Test whether a string is in quotes,
3372 | * if yes return stripped string
3373 | */
3374 | function stripQuotes (str) {
3375 | if (QUOTE_RE.test(str)) {
3376 | return str.slice(1, -1)
3377 | }
3378 | }
3379 | });
3380 | require.register("vue/src/transition.js", function(exports, require, module){
3381 | var endEvents = sniffEndEvents(),
3382 | config = require('./config'),
3383 | // batch enter animations so we only force the layout once
3384 | Batcher = require('./batcher'),
3385 | batcher = new Batcher(),
3386 | // cache timer functions
3387 | setTO = window.setTimeout,
3388 | clearTO = window.clearTimeout,
3389 | // exit codes for testing
3390 | codes = {
3391 | CSS_E : 1,
3392 | CSS_L : 2,
3393 | JS_E : 3,
3394 | JS_L : 4,
3395 | CSS_SKIP : -1,
3396 | JS_SKIP : -2,
3397 | JS_SKIP_E : -3,
3398 | JS_SKIP_L : -4,
3399 | INIT : -5,
3400 | SKIP : -6
3401 | }
3402 |
3403 | // force layout before triggering transitions/animations
3404 | batcher._preFlush = function () {
3405 | /* jshint unused: false */
3406 | var f = document.body.offsetHeight
3407 | }
3408 |
3409 | /**
3410 | * stage:
3411 | * 1 = enter
3412 | * 2 = leave
3413 | */
3414 | var transition = module.exports = function (el, stage, cb, compiler) {
3415 |
3416 | var changeState = function () {
3417 | cb()
3418 | compiler.execHook(stage > 0 ? 'attached' : 'detached')
3419 | }
3420 |
3421 | if (compiler.init) {
3422 | changeState()
3423 | return codes.INIT
3424 | }
3425 |
3426 | var hasTransition = el.vue_trans === '',
3427 | hasAnimation = el.vue_anim === '',
3428 | effectId = el.vue_effect
3429 |
3430 | if (effectId) {
3431 | return applyTransitionFunctions(
3432 | el,
3433 | stage,
3434 | changeState,
3435 | effectId,
3436 | compiler
3437 | )
3438 | } else if (hasTransition || hasAnimation) {
3439 | return applyTransitionClass(
3440 | el,
3441 | stage,
3442 | changeState,
3443 | hasAnimation
3444 | )
3445 | } else {
3446 | changeState()
3447 | return codes.SKIP
3448 | }
3449 |
3450 | }
3451 |
3452 | transition.codes = codes
3453 |
3454 | /**
3455 | * Togggle a CSS class to trigger transition
3456 | */
3457 | function applyTransitionClass (el, stage, changeState, hasAnimation) {
3458 |
3459 | if (!endEvents.trans) {
3460 | changeState()
3461 | return codes.CSS_SKIP
3462 | }
3463 |
3464 | // if the browser supports transition,
3465 | // it must have classList...
3466 | var onEnd,
3467 | classList = el.classList,
3468 | existingCallback = el.vue_trans_cb,
3469 | enterClass = config.enterClass,
3470 | leaveClass = config.leaveClass,
3471 | endEvent = hasAnimation ? endEvents.anim : endEvents.trans
3472 |
3473 | // cancel unfinished callbacks and jobs
3474 | if (existingCallback) {
3475 | el.removeEventListener(endEvent, existingCallback)
3476 | classList.remove(enterClass)
3477 | classList.remove(leaveClass)
3478 | el.vue_trans_cb = null
3479 | }
3480 |
3481 | if (stage > 0) { // enter
3482 |
3483 | // set to enter state before appending
3484 | classList.add(enterClass)
3485 | // append
3486 | changeState()
3487 | // trigger transition
3488 | if (!hasAnimation) {
3489 | batcher.push({
3490 | execute: function () {
3491 | classList.remove(enterClass)
3492 | }
3493 | })
3494 | } else {
3495 | onEnd = function (e) {
3496 | if (e.target === el) {
3497 | el.removeEventListener(endEvent, onEnd)
3498 | el.vue_trans_cb = null
3499 | classList.remove(enterClass)
3500 | }
3501 | }
3502 | el.addEventListener(endEvent, onEnd)
3503 | el.vue_trans_cb = onEnd
3504 | }
3505 | return codes.CSS_E
3506 |
3507 | } else { // leave
3508 |
3509 | if (el.offsetWidth || el.offsetHeight) {
3510 | // trigger hide transition
3511 | classList.add(leaveClass)
3512 | onEnd = function (e) {
3513 | if (e.target === el) {
3514 | el.removeEventListener(endEvent, onEnd)
3515 | el.vue_trans_cb = null
3516 | // actually remove node here
3517 | changeState()
3518 | classList.remove(leaveClass)
3519 | }
3520 | }
3521 | // attach transition end listener
3522 | el.addEventListener(endEvent, onEnd)
3523 | el.vue_trans_cb = onEnd
3524 | } else {
3525 | // directly remove invisible elements
3526 | changeState()
3527 | }
3528 | return codes.CSS_L
3529 |
3530 | }
3531 |
3532 | }
3533 |
3534 | function applyTransitionFunctions (el, stage, changeState, effectId, compiler) {
3535 |
3536 | var funcs = compiler.getOption('effects', effectId)
3537 | if (!funcs) {
3538 | changeState()
3539 | return codes.JS_SKIP
3540 | }
3541 |
3542 | var enter = funcs.enter,
3543 | leave = funcs.leave,
3544 | timeouts = el.vue_timeouts
3545 |
3546 | // clear previous timeouts
3547 | if (timeouts) {
3548 | var i = timeouts.length
3549 | while (i--) {
3550 | clearTO(timeouts[i])
3551 | }
3552 | }
3553 |
3554 | timeouts = el.vue_timeouts = []
3555 | function timeout (cb, delay) {
3556 | var id = setTO(function () {
3557 | cb()
3558 | timeouts.splice(timeouts.indexOf(id), 1)
3559 | if (!timeouts.length) {
3560 | el.vue_timeouts = null
3561 | }
3562 | }, delay)
3563 | timeouts.push(id)
3564 | }
3565 |
3566 | if (stage > 0) { // enter
3567 | if (typeof enter !== 'function') {
3568 | changeState()
3569 | return codes.JS_SKIP_E
3570 | }
3571 | enter(el, changeState, timeout)
3572 | return codes.JS_E
3573 | } else { // leave
3574 | if (typeof leave !== 'function') {
3575 | changeState()
3576 | return codes.JS_SKIP_L
3577 | }
3578 | leave(el, changeState, timeout)
3579 | return codes.JS_L
3580 | }
3581 |
3582 | }
3583 |
3584 | /**
3585 | * Sniff proper transition end event name
3586 | */
3587 | function sniffEndEvents () {
3588 | var el = document.createElement('vue'),
3589 | defaultEvent = 'transitionend',
3590 | events = {
3591 | 'transition' : defaultEvent,
3592 | 'mozTransition' : defaultEvent,
3593 | 'webkitTransition' : 'webkitTransitionEnd'
3594 | },
3595 | ret = {}
3596 | for (var name in events) {
3597 | if (el.style[name] !== undefined) {
3598 | ret.trans = events[name]
3599 | break
3600 | }
3601 | }
3602 | ret.anim = el.style.animation === ''
3603 | ? 'animationend'
3604 | : 'webkitAnimationEnd'
3605 | return ret
3606 | }
3607 | });
3608 | require.register("vue/src/batcher.js", function(exports, require, module){
3609 | var utils = require('./utils')
3610 |
3611 | function Batcher () {
3612 | this.reset()
3613 | }
3614 |
3615 | var BatcherProto = Batcher.prototype
3616 |
3617 | BatcherProto.push = function (job) {
3618 | if (!job.id || !this.has[job.id]) {
3619 | this.queue.push(job)
3620 | this.has[job.id] = job
3621 | if (!this.waiting) {
3622 | this.waiting = true
3623 | utils.nextTick(utils.bind(this.flush, this))
3624 | }
3625 | } else if (job.override) {
3626 | var oldJob = this.has[job.id]
3627 | oldJob.cancelled = true
3628 | this.queue.push(job)
3629 | this.has[job.id] = job
3630 | }
3631 | }
3632 |
3633 | BatcherProto.flush = function () {
3634 | // before flush hook
3635 | if (this._preFlush) this._preFlush()
3636 | // do not cache length because more jobs might be pushed
3637 | // as we execute existing jobs
3638 | for (var i = 0; i < this.queue.length; i++) {
3639 | var job = this.queue[i]
3640 | if (!job.cancelled) {
3641 | job.execute()
3642 | }
3643 | }
3644 | this.reset()
3645 | }
3646 |
3647 | BatcherProto.reset = function () {
3648 | this.has = utils.hash()
3649 | this.queue = []
3650 | this.waiting = false
3651 | }
3652 |
3653 | module.exports = Batcher
3654 | });
3655 | require.register("vue/src/directives/index.js", function(exports, require, module){
3656 | var utils = require('../utils'),
3657 | config = require('../config'),
3658 | transition = require('../transition'),
3659 | directives = module.exports = utils.hash()
3660 |
3661 | /**
3662 | * Nest and manage a Child VM
3663 | */
3664 | directives.component = {
3665 | isLiteral: true,
3666 | bind: function () {
3667 | if (!this.el.vue_vm) {
3668 | this.childVM = new this.Ctor({
3669 | el: this.el,
3670 | parent: this.vm
3671 | })
3672 | }
3673 | },
3674 | unbind: function () {
3675 | if (this.childVM) {
3676 | this.childVM.$destroy()
3677 | }
3678 | }
3679 | }
3680 |
3681 | /**
3682 | * Binding HTML attributes
3683 | */
3684 | directives.attr = {
3685 | bind: function () {
3686 | var params = this.vm.$options.paramAttributes
3687 | this.isParam = params && params.indexOf(this.arg) > -1
3688 | },
3689 | update: function (value) {
3690 | if (value || value === 0) {
3691 | this.el.setAttribute(this.arg, value)
3692 | } else {
3693 | this.el.removeAttribute(this.arg)
3694 | }
3695 | if (this.isParam) {
3696 | this.vm[this.arg] = utils.checkNumber(value)
3697 | }
3698 | }
3699 | }
3700 |
3701 | /**
3702 | * Binding textContent
3703 | */
3704 | directives.text = {
3705 | bind: function () {
3706 | this.attr = this.el.nodeType === 3
3707 | ? 'nodeValue'
3708 | : 'textContent'
3709 | },
3710 | update: function (value) {
3711 | this.el[this.attr] = utils.guard(value)
3712 | }
3713 | }
3714 |
3715 | /**
3716 | * Binding CSS display property
3717 | */
3718 | directives.show = function (value) {
3719 | var el = this.el,
3720 | target = value ? '' : 'none',
3721 | change = function () {
3722 | el.style.display = target
3723 | }
3724 | transition(el, value ? 1 : -1, change, this.compiler)
3725 | }
3726 |
3727 | /**
3728 | * Binding CSS classes
3729 | */
3730 | directives['class'] = function (value) {
3731 | if (this.arg) {
3732 | utils[value ? 'addClass' : 'removeClass'](this.el, this.arg)
3733 | } else {
3734 | if (this.lastVal) {
3735 | utils.removeClass(this.el, this.lastVal)
3736 | }
3737 | if (value) {
3738 | utils.addClass(this.el, value)
3739 | this.lastVal = value
3740 | }
3741 | }
3742 | }
3743 |
3744 | /**
3745 | * Only removed after the owner VM is ready
3746 | */
3747 | directives.cloak = {
3748 | isEmpty: true,
3749 | bind: function () {
3750 | var el = this.el
3751 | this.compiler.observer.once('hook:ready', function () {
3752 | el.removeAttribute(config.prefix + '-cloak')
3753 | })
3754 | }
3755 | }
3756 |
3757 | /**
3758 | * Store a reference to self in parent VM's $
3759 | */
3760 | directives.ref = {
3761 | isLiteral: true,
3762 | bind: function () {
3763 | var id = this.expression
3764 | if (id) {
3765 | this.vm.$parent.$[id] = this.vm
3766 | }
3767 | },
3768 | unbind: function () {
3769 | var id = this.expression
3770 | if (id) {
3771 | delete this.vm.$parent.$[id]
3772 | }
3773 | }
3774 | }
3775 |
3776 | directives.on = require('./on')
3777 | directives.repeat = require('./repeat')
3778 | directives.model = require('./model')
3779 | directives['if'] = require('./if')
3780 | directives['with'] = require('./with')
3781 | directives.html = require('./html')
3782 | directives.style = require('./style')
3783 | directives.partial = require('./partial')
3784 | directives.view = require('./view')
3785 | });
3786 | require.register("vue/src/directives/if.js", function(exports, require, module){
3787 | var utils = require('../utils')
3788 |
3789 | /**
3790 | * Manages a conditional child VM
3791 | */
3792 | module.exports = {
3793 |
3794 | bind: function () {
3795 |
3796 | this.parent = this.el.parentNode
3797 | this.ref = document.createComment('vue-if')
3798 | this.Ctor = this.compiler.resolveComponent(this.el)
3799 |
3800 | // insert ref
3801 | this.parent.insertBefore(this.ref, this.el)
3802 | this.parent.removeChild(this.el)
3803 |
3804 | if (utils.attr(this.el, 'view')) {
3805 | utils.warn(
3806 | 'Conflict: v-if cannot be used together with v-view. ' +
3807 | 'Just set v-view\'s binding value to empty string to empty it.'
3808 | )
3809 | }
3810 | if (utils.attr(this.el, 'repeat')) {
3811 | utils.warn(
3812 | 'Conflict: v-if cannot be used together with v-repeat. ' +
3813 | 'Use `v-show` or the `filterBy` filter instead.'
3814 | )
3815 | }
3816 | },
3817 |
3818 | update: function (value) {
3819 |
3820 | if (!value) {
3821 | this._unbind()
3822 | } else if (!this.childVM) {
3823 | this.childVM = new this.Ctor({
3824 | el: this.el.cloneNode(true),
3825 | parent: this.vm
3826 | })
3827 | if (this.compiler.init) {
3828 | this.parent.insertBefore(this.childVM.$el, this.ref)
3829 | } else {
3830 | this.childVM.$before(this.ref)
3831 | }
3832 | }
3833 |
3834 | },
3835 |
3836 | unbind: function () {
3837 | if (this.childVM) {
3838 | this.childVM.$destroy()
3839 | this.childVM = null
3840 | }
3841 | }
3842 | }
3843 | });
3844 | require.register("vue/src/directives/repeat.js", function(exports, require, module){
3845 | var utils = require('../utils'),
3846 | config = require('../config')
3847 |
3848 | /**
3849 | * Binding that manages VMs based on an Array
3850 | */
3851 | module.exports = {
3852 |
3853 | bind: function () {
3854 |
3855 | this.identifier = '$r' + this.id
3856 |
3857 | // a hash to cache the same expressions on repeated instances
3858 | // so they don't have to be compiled for every single instance
3859 | this.expCache = utils.hash()
3860 |
3861 | var el = this.el,
3862 | ctn = this.container = el.parentNode
3863 |
3864 | // extract child Id, if any
3865 | this.childId = this.compiler.eval(utils.attr(el, 'ref'))
3866 |
3867 | // create a comment node as a reference node for DOM insertions
3868 | this.ref = document.createComment(config.prefix + '-repeat-' + this.key)
3869 | ctn.insertBefore(this.ref, el)
3870 | ctn.removeChild(el)
3871 |
3872 | this.collection = null
3873 | this.vms = null
3874 |
3875 | },
3876 |
3877 | update: function (collection) {
3878 |
3879 | if (!Array.isArray(collection)) {
3880 | if (utils.isObject(collection)) {
3881 | collection = utils.objectToArray(collection)
3882 | } else {
3883 | utils.warn('v-repeat only accepts Array or Object values.')
3884 | }
3885 | }
3886 |
3887 | // keep reference of old data and VMs
3888 | // so we can reuse them if possible
3889 | this.oldVMs = this.vms
3890 | this.oldCollection = this.collection
3891 | collection = this.collection = collection || []
3892 |
3893 | var isObject = collection[0] && utils.isObject(collection[0])
3894 | this.vms = this.oldCollection
3895 | ? this.diff(collection, isObject)
3896 | : this.init(collection, isObject)
3897 |
3898 | if (this.childId) {
3899 | this.vm.$[this.childId] = this.vms
3900 | }
3901 |
3902 | },
3903 |
3904 | init: function (collection, isObject) {
3905 | var vm, vms = []
3906 | for (var i = 0, l = collection.length; i < l; i++) {
3907 | vm = this.build(collection[i], i, isObject)
3908 | vms.push(vm)
3909 | if (this.compiler.init) {
3910 | this.container.insertBefore(vm.$el, this.ref)
3911 | } else {
3912 | vm.$before(this.ref)
3913 | }
3914 | }
3915 | return vms
3916 | },
3917 |
3918 | /**
3919 | * Diff the new array with the old
3920 | * and determine the minimum amount of DOM manipulations.
3921 | */
3922 | diff: function (newCollection, isObject) {
3923 |
3924 | var i, l, item, vm,
3925 | oldIndex,
3926 | targetNext,
3927 | currentNext,
3928 | nextEl,
3929 | ctn = this.container,
3930 | oldVMs = this.oldVMs,
3931 | vms = []
3932 |
3933 | vms.length = newCollection.length
3934 |
3935 | // first pass, collect new reused and new created
3936 | for (i = 0, l = newCollection.length; i < l; i++) {
3937 | item = newCollection[i]
3938 | if (isObject) {
3939 | item.$index = i
3940 | if (item.__emitter__ && item.__emitter__[this.identifier]) {
3941 | // this piece of data is being reused.
3942 | // record its final position in reused vms
3943 | item.$reused = true
3944 | } else {
3945 | vms[i] = this.build(item, i, isObject)
3946 | }
3947 | } else {
3948 | // we can't attach an identifier to primitive values
3949 | // so have to do an indexOf...
3950 | oldIndex = indexOf(oldVMs, item)
3951 | if (oldIndex > -1) {
3952 | // record the position on the existing vm
3953 | oldVMs[oldIndex].$reused = true
3954 | oldVMs[oldIndex].$data.$index = i
3955 | } else {
3956 | vms[i] = this.build(item, i, isObject)
3957 | }
3958 | }
3959 | }
3960 |
3961 | // second pass, collect old reused and destroy unused
3962 | for (i = 0, l = oldVMs.length; i < l; i++) {
3963 | vm = oldVMs[i]
3964 | item = this.arg
3965 | ? vm.$data[this.arg]
3966 | : vm.$data
3967 | if (item.$reused) {
3968 | vm.$reused = true
3969 | delete item.$reused
3970 | }
3971 | if (vm.$reused) {
3972 | // update the index to latest
3973 | vm.$index = item.$index
3974 | // the item could have had a new key
3975 | if (item.$key && item.$key !== vm.$key) {
3976 | vm.$key = item.$key
3977 | }
3978 | vms[vm.$index] = vm
3979 | } else {
3980 | // this one can be destroyed.
3981 | if (item.__emitter__) {
3982 | delete item.__emitter__[this.identifier]
3983 | }
3984 | vm.$destroy()
3985 | }
3986 | }
3987 |
3988 | // final pass, move/insert DOM elements
3989 | i = vms.length
3990 | while (i--) {
3991 | vm = vms[i]
3992 | item = vm.$data
3993 | targetNext = vms[i + 1]
3994 | if (vm.$reused) {
3995 | nextEl = vm.$el.nextSibling
3996 | // destroyed VMs' element might still be in the DOM
3997 | // due to transitions
3998 | while (!nextEl.vue_vm && nextEl !== this.ref) {
3999 | nextEl = nextEl.nextSibling
4000 | }
4001 | currentNext = nextEl.vue_vm
4002 | if (currentNext !== targetNext) {
4003 | if (!targetNext) {
4004 | ctn.insertBefore(vm.$el, this.ref)
4005 | } else {
4006 | nextEl = targetNext.$el
4007 | // new VMs' element might not be in the DOM yet
4008 | // due to transitions
4009 | while (!nextEl.parentNode) {
4010 | targetNext = vms[nextEl.vue_vm.$index + 1]
4011 | nextEl = targetNext
4012 | ? targetNext.$el
4013 | : this.ref
4014 | }
4015 | ctn.insertBefore(vm.$el, nextEl)
4016 | }
4017 | }
4018 | delete vm.$reused
4019 | delete item.$index
4020 | delete item.$key
4021 | } else { // a new vm
4022 | vm.$before(targetNext ? targetNext.$el : this.ref)
4023 | }
4024 | }
4025 |
4026 | return vms
4027 | },
4028 |
4029 | build: function (data, index, isObject) {
4030 |
4031 | // wrap non-object values
4032 | var raw, alias,
4033 | wrap = !isObject || this.arg
4034 | if (wrap) {
4035 | raw = data
4036 | alias = this.arg || '$value'
4037 | data = {}
4038 | data[alias] = raw
4039 | }
4040 | data.$index = index
4041 |
4042 | var el = this.el.cloneNode(true),
4043 | Ctor = this.compiler.resolveComponent(el, data),
4044 | vm = new Ctor({
4045 | el: el,
4046 | data: data,
4047 | parent: this.vm,
4048 | compilerOptions: {
4049 | repeat: true,
4050 | expCache: this.expCache
4051 | }
4052 | })
4053 |
4054 | if (isObject) {
4055 | // attach an ienumerable identifier to the raw data
4056 | (raw || data).__emitter__[this.identifier] = true
4057 | }
4058 |
4059 | if (wrap) {
4060 | var self = this,
4061 | sync = function (val) {
4062 | self.lock = true
4063 | self.collection.$set(vm.$index, val)
4064 | self.lock = false
4065 | }
4066 | vm.$compiler.observer.on('change:' + alias, sync)
4067 | }
4068 |
4069 | return vm
4070 |
4071 | },
4072 |
4073 | unbind: function () {
4074 | if (this.childId) {
4075 | delete this.vm.$[this.childId]
4076 | }
4077 | if (this.vms) {
4078 | var i = this.vms.length
4079 | while (i--) {
4080 | this.vms[i].$destroy()
4081 | }
4082 | }
4083 | }
4084 | }
4085 |
4086 | // Helpers --------------------------------------------------------------------
4087 |
4088 | /**
4089 | * Find an object or a wrapped data object
4090 | * from an Array
4091 | */
4092 | function indexOf (vms, obj) {
4093 | for (var vm, i = 0, l = vms.length; i < l; i++) {
4094 | vm = vms[i]
4095 | if (!vm.$reused && vm.$value === obj) {
4096 | return i
4097 | }
4098 | }
4099 | return -1
4100 | }
4101 | });
4102 | require.register("vue/src/directives/on.js", function(exports, require, module){
4103 | var utils = require('../utils')
4104 |
4105 | /**
4106 | * Binding for event listeners
4107 | */
4108 | module.exports = {
4109 |
4110 | isFn: true,
4111 |
4112 | bind: function () {
4113 | this.context = this.binding.isExp
4114 | ? this.vm
4115 | : this.binding.compiler.vm
4116 | },
4117 |
4118 | update: function (handler) {
4119 | if (typeof handler !== 'function') {
4120 | utils.warn('Directive "v-on:' + this.expression + '" expects a method.')
4121 | return
4122 | }
4123 | this._unbind()
4124 | var vm = this.vm,
4125 | context = this.context
4126 | this.handler = function (e) {
4127 | e.targetVM = vm
4128 | context.$event = e
4129 | var res = handler.call(context, e)
4130 | context.$event = null
4131 | return res
4132 | }
4133 | this.el.addEventListener(this.arg, this.handler)
4134 | },
4135 |
4136 | unbind: function () {
4137 | this.el.removeEventListener(this.arg, this.handler)
4138 | }
4139 | }
4140 | });
4141 | require.register("vue/src/directives/model.js", function(exports, require, module){
4142 | var utils = require('../utils'),
4143 | isIE9 = navigator.userAgent.indexOf('MSIE 9.0') > 0,
4144 | filter = [].filter
4145 |
4146 | /**
4147 | * Returns an array of values from a multiple select
4148 | */
4149 | function getMultipleSelectOptions (select) {
4150 | return filter
4151 | .call(select.options, function (option) {
4152 | return option.selected
4153 | })
4154 | .map(function (option) {
4155 | return option.value || option.text
4156 | })
4157 | }
4158 |
4159 | /**
4160 | * Two-way binding for form input elements
4161 | */
4162 | module.exports = {
4163 |
4164 | bind: function () {
4165 |
4166 | var self = this,
4167 | el = self.el,
4168 | type = el.type,
4169 | tag = el.tagName
4170 |
4171 | self.lock = false
4172 | self.ownerVM = self.binding.compiler.vm
4173 |
4174 | // determine what event to listen to
4175 | self.event =
4176 | (self.compiler.options.lazy ||
4177 | tag === 'SELECT' ||
4178 | type === 'checkbox' || type === 'radio')
4179 | ? 'change'
4180 | : 'input'
4181 |
4182 | // determine the attribute to change when updating
4183 | self.attr = type === 'checkbox'
4184 | ? 'checked'
4185 | : (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA')
4186 | ? 'value'
4187 | : 'innerHTML'
4188 |
4189 | // select[multiple] support
4190 | if(tag === 'SELECT' && el.hasAttribute('multiple')) {
4191 | this.multi = true
4192 | }
4193 |
4194 | var compositionLock = false
4195 | self.cLock = function () {
4196 | compositionLock = true
4197 | }
4198 | self.cUnlock = function () {
4199 | compositionLock = false
4200 | }
4201 | el.addEventListener('compositionstart', this.cLock)
4202 | el.addEventListener('compositionend', this.cUnlock)
4203 |
4204 | // attach listener
4205 | self.set = self.filters
4206 | ? function () {
4207 | if (compositionLock) return
4208 | // if this directive has filters
4209 | // we need to let the vm.$set trigger
4210 | // update() so filters are applied.
4211 | // therefore we have to record cursor position
4212 | // so that after vm.$set changes the input
4213 | // value we can put the cursor back at where it is
4214 | var cursorPos
4215 | try { cursorPos = el.selectionStart } catch (e) {}
4216 |
4217 | self._set()
4218 |
4219 | // since updates are async
4220 | // we need to reset cursor position async too
4221 | utils.nextTick(function () {
4222 | if (cursorPos !== undefined) {
4223 | el.setSelectionRange(cursorPos, cursorPos)
4224 | }
4225 | })
4226 | }
4227 | : function () {
4228 | if (compositionLock) return
4229 | // no filters, don't let it trigger update()
4230 | self.lock = true
4231 |
4232 | self._set()
4233 |
4234 | utils.nextTick(function () {
4235 | self.lock = false
4236 | })
4237 | }
4238 | el.addEventListener(self.event, self.set)
4239 |
4240 | // fix shit for IE9
4241 | // since it doesn't fire input on backspace / del / cut
4242 | if (isIE9) {
4243 | self.onCut = function () {
4244 | // cut event fires before the value actually changes
4245 | utils.nextTick(function () {
4246 | self.set()
4247 | })
4248 | }
4249 | self.onDel = function (e) {
4250 | if (e.keyCode === 46 || e.keyCode === 8) {
4251 | self.set()
4252 | }
4253 | }
4254 | el.addEventListener('cut', self.onCut)
4255 | el.addEventListener('keyup', self.onDel)
4256 | }
4257 | },
4258 |
4259 | _set: function () {
4260 | this.ownerVM.$set(
4261 | this.key, this.multi
4262 | ? getMultipleSelectOptions(this.el)
4263 | : this.el[this.attr]
4264 | )
4265 | },
4266 |
4267 | update: function (value, init) {
4268 | /* jshint eqeqeq: false */
4269 | // sync back inline value if initial data is undefined
4270 | if (init && value === undefined) {
4271 | return this._set()
4272 | }
4273 | if (this.lock) return
4274 | var el = this.el
4275 | if (el.tagName === 'SELECT') { // select dropdown
4276 | el.selectedIndex = -1
4277 | if(this.multi && Array.isArray(value)) {
4278 | value.forEach(this.updateSelect, this)
4279 | } else {
4280 | this.updateSelect(value)
4281 | }
4282 | } else if (el.type === 'radio') { // radio button
4283 | el.checked = value == el.value
4284 | } else if (el.type === 'checkbox') { // checkbox
4285 | el.checked = !!value
4286 | } else {
4287 | el[this.attr] = utils.guard(value)
4288 | }
4289 | },
4290 |
4291 | updateSelect: function (value) {
4292 | /* jshint eqeqeq: false */
4293 | // setting