рднреБрдЧрддрд╛рди рдХреЗ рд▓рд┐рдП рдЪрд╛рд▓рд╛рдиред Sails.js, ractive.js, Backbone.js рдкрд░ рдХрд╛рд░реНрдп рдЕрдиреБрдкреНрд░рдпреЛрдЧ





рдЕрдЪреНрдЫреЗ рджрд┐рди, рд╕рдкреНрддрд╛рд╣рд╛рдВрдд рдореЗрдВ, рдмреЛрд░рд┐рдпрдд рдФрд░ рдХрд╛рдо рдХреА рдХрдореА рд╕реЗ, рдореИрдВрдиреЗ рдПрдХ рдЫреЛрдЯрд╛ рд╕рд╛ рдЖрд╡реЗрджрди рд▓рд┐рдЦрдХрд░ рдЦреБрдж рдХрд╛ рдордиреЛрд░рдВрдЬрди рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдЬреЛ рджреЛ рдЕрджреНрднреБрдд рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХреА рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢реИрдХреНрд╖рд┐рдХ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░реЗрдЧрд╛ - ractive.js рдФрд░ sails.js



рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдмрдпрд╛рди


рдХрд╛рдо рдХреЗ рдмрд╛рдж, рдПрдХ рдХреЛ рдЕрдХреНрд╕рд░ рдЕрдЧрд▓реЗ рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж (рдореИрдВ рдПрдХ рдлреНрд░реАрд▓рд╛рдВрд╕рд░ рд╣реВрдВ) рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рднреБрдЧрддрд╛рди рдХреЗ рд▓рд┐рдП рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдЪрд╛рд▓рд╛рди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдЦрд╛рд╕рдХрд░ рдпрджрд┐ рдЖрдк рдХрд╛рдиреВрдиреА рд╕рдВрд╕реНрдерд╛рдУрдВ рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдПрдХ рд╕рд░рд▓ HTML-рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд┐рд╕рдореЗрдВ рдореИрдВрдиреЗ рдЕрдкрдиреЗ рд╣рд╛рдереЛрдВ рд╕реЗ рдбреЗрдЯрд╛ рджрд░реНрдЬ рдХрд┐рдпрд╛, рдЕрдЧрд▓реЗ рд╡рд╛рд▓реЗ рдХреЛ рд╕рд╣реА рдХрд┐рдпрд╛ ...



рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ



рдЫрд╡рд┐



рдореИрдВ рдорд╛рдирддрд╛ рд╣реВрдВ, рд╢реИрд▓рд┐рдпреЛрдВ рдФрд░ рд▓реЗрдЖрдЙрдЯ freshbooks.com рд╕реЗ рдЪреБрд░рд╛рдП рдЧрдП рд╣реИрдВ, рдЬреЛ рдореИрдВрдиреЗ рдЕрдкрдиреЗ рд╕рдордп рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдерд╛ред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рд░реВрд╕реА рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЗ рд▓рд┐рдП рдпрд╣ рдореБрдЭреЗ рд╕реВрдЯ рдирд╣реАрдВ рдХрд░рддрд╛ рдерд╛, рдФрд░ рдореЗрд░реЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ html-рдЯреЗрдореНрдкрд▓реЗрдЯ рдкрд░реНрдпрд╛рдкреНрдд рдерд╛ред



рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХреА рдЪрдпрди


рд╕рднреА рдзрд╛рд░рд┐рдпреЛрдВ рдФрд░ рд╕рд░реНрд╡рд░-рд╕рд╛рдЗрдб js рд╡рд┐рдХрд╛рд╕ рдХреЗ js- рдЪреМрдЦрдЯреЗ рдХреА рд▓реЛрдХрдкреНрд░рд┐рдпрддрд╛ рдХреА рд╡рд░реНрддрдорд╛рди рдкреНрд░рд╡реГрддреНрддрд┐ рдореЗрдВ, рдореИрдВ рдХреБрдЫ рд╕реНрд╡рд╛рджрд┐рд╖реНрдЯ рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ рддрд╛рдХрд┐ рдереЛрдбрд╝реА рд╕реА рдЦреБрд╢реА рдХреЗ рд▓рд┐рдП рдереЛрдбрд╝рд╛ js рд░рд╣ рд╕рдХреЗ ... рдФрд░ рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдЗрди рдЦрд┐рд▓реМрдиреЛрдВ рдХреЛ рдЖрдЬрд╝рдорд╛рдПрдВред



рдХреБрдЫ рдЕрдзреНрдпрдпрди, рддреБрд▓рдирд╛ рдФрд░ рд╕рд╣рдЬ рдЬреНрдЮрд╛рди рдпреБрдХреНрдд рдЕрдВрддрд░реНрджреГрд╖реНрдЯрд┐ рдХреЗ рдмрд╛рдж, рдореИрдВ рдПрдХ рд╕рд░реНрд╡рд░ рдХреЗ рд░реВрдк рдореЗрдВ sails.js рдкрд░ рдмрд╕ рдЧрдпрд╛ред рдореИрдВрдиреЗ рдбрд░реНрдмреА рдФрд░ рдкрд╛рд▓ рдХреЗ рдмреАрдЪ рдЪреБрдирд╛ - рдЕрдВрдд рдореЗрдВ рдореИрдВрдиреЗ рдПрдХ рд╕реЗрд▓рдмреЛрдЯ рдЪреБрдирд╛, рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдЗрд╕рдХреА рд╕рд╛рджрдЧреА (рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдбреЙрдХ рдЖрд╕рд╛рди рд╣реИ рдФрд░ рдЕрдЪреНрдЫрд╛ рд╣реИ) рдХреЗ рдХрд╛рд░рдг, рдЗрд╕рдореЗрдВ рдмреЙрдХреНрд╕ рдХреЗ рдмрд╛рд╣рд░ рдПрдХ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдмрд╛рдХреА рдПрдкреА рдЬрдирд░реЗрдЯрд░ рднреА рд╣реИред рд╕реАрдЦрдиреЗ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдбрд░реНрдмреА рдХрдард┐рди рдФрд░ рдЕрдзрд┐рдХ рд░рд╛рдХреНрд╖рд╕реА рд▓рдЧ рд░рд╣рд╛ рдерд╛ (рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП - рдПрдХ рд╕реНрдкрд╖реНрдЯ рдЙрдкрд░рд┐)ред



рдХреНрд▓рд╛рдЗрдВрдЯ рдкрд░ рдореИрдВрдиреЗ ractive.js рдХреЗ рд╕рд╛рде рдЦреЗрд▓рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдФрд░ рдмрд╛рдж рдореЗрдВ рдмреИрдХрдмреЛрди.рдЬреЗрдПрд╕ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛ рдЧрдпрд╛ - рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдореЙрдбрд▓ рдХреЗ рд╕рд╛рде рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдХрд╛рдо рдХреЗ рдХрд╛рд░рдгред



рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдкрд╣рд▓реЗ, рдореБрдЭреЗ sails.js рдФрд░ ractive.js рдХрд╛ рдЕрдиреБрднрд╡ рдирд╣реАрдВ рдерд╛ред рдХрд╛рдо рдореЗрдВ рдореИрдВрдиреЗ рдХреЗрд╡рд▓ рд░реАрдврд╝ рдХреА рд╣рдбреНрдбреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред

рдЖрдЗрдП рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ,



рд╕рд░реНрд╡рд░



рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдо sails v0.10 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ - рдпрд╣ рдЕрднреА рднреА рдмреАрдЯрд╛ рдореЗрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рд░ рд╕рдВрд╕реНрдХрд░рдг 0.9.x рдХреА рддреБрд▓рдирд╛ рдореЗрдВ, рдЗрд╕рдореЗрдВ рдХрдИ рдЕрдЪреНрдЫреЗ рд╣реИрдВ рдЬреЛ рдХрд╛рдо рдореЗрдВ рдЖрддреЗ рд╣реИрдВред рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ, рдореЙрдбрд▓ рдЕрд╕реЛрдХреЗрд╢рди , рдЬреЛ рдЖрдкрдХреЛ рдПрдХ-рд╕реЗ-рдХрдИ, рдХрдИ-рд╕реЗ-рдХрдИ (рдФрд░ рдореЙрдбрд▓ рдХреЗ рдмреАрдЪ рдЕрдиреНрдп рд╕рдВрдмрдВрдзреЛрдВ) рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рд╡рд╣ рднреА 0.10 рдореЗрдВ рдЧреНрд░рдВрдЯ рдЯрд╛рд╕реНрдХ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдлрд┐рд░ рд╕реЗ рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЧреЛрджреА рдореЗрдВ 0.10 рдкрд░, рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ



s0 v0.10 рдХреЛ npm рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╡рд┐рддрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ (рдореИрдВрдиреЗ рд╡рд┐рд╢реНрд╡ рд╕реНрддрд░ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рд╣реИ)

sudo npm install -g "git://github.com/balderdashy/sails.git#v0.10"
      
      





рдЪреЗрдХ

 sails -v
      
      





0.10.0 - рдЙрддреНрдХреГрд╖реНрдЯ



рдПрдХ рдХрдВрдХрд╛рд▓ sailsjs рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдмрдирд╛рдирд╛


рд╣рдо рдПрдХ рдирдпрд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрдирд╡реЙрдпрд╕рд░ рдФрд░ рдирд┐рд░реНрднрд░рддрд╛

 sails new invoicer cd invoicer npm install
      
      





рдЕрдЧрд▓рд╛, sails lift



рдХрдорд╛рдВрдб рдХреЛ рдЪрд▓рд╛рдХрд░, рдЖрдк рдмрд┐рд▓реНрдЯ-рдЗрди рдПрдХреНрд╕рдкреНрд░реЗрд╕.рдЬреЗрдПрд╕ рд╕рд░реНрд╡рд░ рдХреЛ рдЪрд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ localhost:1337







API рдЗрдХрд╛рдЗрдпрд╛рдБ рдмрдирд╛рдирд╛ (рдореЙрдбрд▓)


рд╣рдо рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП 3 рдореЙрдбрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА:



sails generate api <api_name>



рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ sails generate api <api_name>





рдПрдкреАрдЖрдИ рдкреАрдврд╝реА
 zaebee@zaeboo$ sails generate api user debug: Generated a new model `User` at api/models/User.js! debug: Generated a new controller `user` at api/controllers/UserController.js! info: REST API generated @ http://localhost:1337/user info: and will be available the next time you run `sails lift`. zaebee@zaeboo$ sails generate api invoice debug: Generated a new model `Invoice` at api/models/Invoice.js! debug: Generated a new controller `invoice` at api/controllers/InvoiceController.js! info: REST API generated @ http://localhost:1337/invoice info: and will be available the next time you run `sails lift`. zaebee@zaeboo$ sails generate api task debug: Generated a new controller `task` at api/controllers/TaskController.js! debug: Generated a new model `Task` at api/models/Task.js! info: REST API generated @ http://localhost:1337/task info: and will be available the next time you run `sails lift`.
      
      







рдЙрд╕рдХреЗ рдмрд╛рдж, рдПрдкреАрдЖрдИ / рдирд┐рдпрдВрддреНрд░рдХ рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ 3 рдлрд╛рдЗрд▓реЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреА

 -rw-r--r-- 1 146  28 17:15 InvoiceController.js -rw-r--r-- 1 143  28 17:15 TaskController.js -rw-r--r-- 1 143  28 17:15 UserController.js
      
      





рдПрдкреАрдЖрдИ / рдореЙрдбрд▓ рднреА

 -rw-r--r-- 1 146  28 17:15 Invoice.js -rw-r--r-- 1 143  28 17:15 Task.js -rw-r--r-- 1 143  28 17:15 User.js
      
      







рдЖрд╕рд╛рди рдФрд░ рд╕рд░рд▓ рдкрд╛рд▓реЛрдВ рдиреЗ рд╣рдорд╛рд░реЗ рд▓рд┐рдП 3 рддрд░реАрдХреЗ рдмрдирд╛рдП,

localhost:1337/user





localhost:1337/invoice





localhost:1337/task





рдЬреЛ CRUD рдСрдкрд░реЗрд╢рди рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддреЗ рд╣реИрдВред рдЙрдирдХреЗ рд▓рд┐рдП рднреА рдЙрдкрдирд╛рдо рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, localhost:1337/user/create?name=Andrey&address=Russia



localhost:1337/user/create?name=Andrey&address=Russia



- рдПрдХ рдирдпрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдПрдЧрд╛ред рдЖрдк рдкреЛрд╕реНрдЯрдореИрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЦреЗрд▓ рд╕рдХрддреЗ рд╣реИрдВ



рдореИрдВ рдЖрдкрдХреЛ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдкрд░ рдкреНрд░рд▓реЗрдЦрди рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рднреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВ



рднрдВрдбрд╛рд░рдг рд╡рд┐рдиреНрдпрд╛рд╕ (DB)


рдирд┐рд░реНрдорд┐рдд рдбреЗрдЯрд╛ рдХрд╣рд╛рдБ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ? рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рдПрдХ рдбрд┐рд╕реНрдХ рдХреЛ рднрдВрдбрд╛рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдХрд┐ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ config/connections.js



config/models.js



рдФрд░ config/models.js



рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ

config / connection.js рдХреЛрдб
 module.exports.connections = { localDiskDb: { adapter: 'sails-disk' }, someMysqlServer: { adapter : 'sails-mysql', host : 'YOUR_MYSQL_SERVER_HOSTNAME_OR_IP_ADDRESS', user : 'YOUR_MYSQL_USER', password: 'YOUR_MYSQL_PASSWORD', database: 'YOUR_MYSQL_DB' }, someMongodbServer: { adapter : 'sails-mongo', host : 'localhost', port : 27017, //user : 'username', //password : 'password', database : 'invoicer' }, somePostgresqlServer: { adapter : 'sails-postgresql', host : 'YOUR_POSTGRES_SERVER_HOSTNAME_OR_IP_ADDRESS', user : 'YOUR_POSTGRES_USER', password : 'YOUR_POSTGRES_PASSWORD', database : 'YOUR_POSTGRES_DB' } };
      
      







рд╣рдо рдЕрднрд┐рд▓реЗрдЦреЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдореЛрдВрдЧреЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рдХреЙрдиреНрдлрд┐рдЧ / рдореЙрдбрд▓реНрд╕ рдХреЛ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░реЗрдВрдЧреЗред

config / model.js рдХреЛрдб
 /** * Models * (sails.config.models) * * Unless you override them, the following properties will be included * in each of your models. */ module.exports.models = { // Your app's default connection. // ie the name of one of your app's connections (see `config/connections.js`) // // (defaults to localDiskDb) connection: 'someMongodbServer' };
      
      







рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛, рдЗрдирд╡реЙрдЗрд╕ рдФрд░ рдЯрд╛рд╕реНрдХ рдореЙрдбрд▓ рдХреЗ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рдирдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ

рдПрдкреАрдЖрдИ / рдореЙрдбрд▓ / User.js
 module.exports = { attributes: { name: 'string', email: 'string', avatar: 'string', address: 'text', account: 'text', invoices: { collection: 'invoice', via: 'owner', } }, };
      
      







рдПрдкреАрдЖрдИ / рдореЙрдбрд▓ / рдЪрд╛рд▓рд╛рди.рдЬреЗрдПрд╕
 module.exports = { attributes: { total_amount: 'float', name: 'string', address: 'text', owner: { required: false, model: 'user', }, tasks: { required: false, collection: 'task', via: 'invoice', } }, };
      
      







рдПрдкреАрдЖрдИ / рдореЙрдбрд▓ / рдЯрд╛рд╕реНрдХ.рдЬреЗрдПрд╕
 module.exports = { attributes: { name: 'string', description: 'text', hours: 'float', rate: 'float', invoice: { required: false, model: 'invoice', via: 'tasks', } }, };
      
      







рдореЛрдВрдЧреЛ рдПрдбреЙрдкреНрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкрд╛рд▓реНрд╕-рдореЛрдВрдЧреЛ рдкреИрдХреЗрдЬ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛

 npm install sails-mongo@0.10
      
      







рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреЗ рд▓рд┐рдП `рдПрдХреНрд╢рди` рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдЯреЗрдореНрдкреНрд▓реЗрдЯ (рджреГрд╢реНрдп) рдЬреЛрдбрд╝рдирд╛


рд╣рдореЗрдВ рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬреЛ рд╣рдорд╛рд░реЗ рдореБрдЦреНрдп рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдПрдХ рдкреГрд╖реНрда рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛ (рдПрдХ рдЪрд╛рд▓рд╛рди рдмрдирд╛рдирд╛):

 sails generate controller main generate
      
      





рд╣рдордиреЗ рдПрдХ рдирдпрд╛ MainController.js



рдмрдирд╛рдпрд╛, рдЬрд┐рд╕рдореЗрдВ рдПрдХ generate



рдлрдВрдХреНрд╢рди рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддрдерд╛рдХрдерд┐рдд рдПрдХреНрд╢рди

рдпрджрд┐ рдЖрдк url рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВ localhost:1337/main/generate



localhost:1337/main/generate



рд╣рдо рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ generate



рдлрдВрдХреНрд╢рди рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреНрдпрд╛ рд╣реИ

рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдпрд╣ json рд▓реМрдЯрд╛ рджреЗрдЧрд╛

 return res.json({ todo: 'Not implemented yet!' });
      
      





рд╣рдо рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ html рдкреЗрдЬ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЙрдкрд░реЛрдХреНрдд рдХреЛрдб рдХреЛ рдмрджрд▓реЗрдВ

 return res.view()
      
      





рд╣рдо рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдкреГрд╖реНрда рддрд╛рдЬрд╝рд╛ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рджреЗрдЦрддреЗ рд╣реИрдВ

 { "view": { "name": "main/generate", "root": "/home/zaebee/projects/invoicer/views", "defaultEngine": "ejs", "ext": ".ejs" } }
      
      





рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рд╣рдордиреЗ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдЦрд╛рдХрд╛ рдирд╣реАрдВ рдмрдирд╛рдпрд╛ рд╣реИред рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рднреА HTML рдЯреЗрдореНрдкреНрд▓реЗрдЯ рджреГрд╢реНрдп рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╣реИрдВ рдФрд░ рдЙрдирдХреЗ рдкрд╛рд╕ рдирд┐рдореНрди views/<controller_name>/<action_name>







рдПрдХ рдЦрд╛рд▓реА рджреГрд╢реНрдп / рдореБрдЦреНрдп / рдЙрддреНрдкрдиреНрди рдЯреЗрдореНрдкрд▓реЗрдЯ рдмрдирд╛рдПрдБ

 zaebee@zaeboo$ mkdir views/main zaebee@zaeboo$ touch views/main/generate.ejs
      
      





рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, ejs рдХрд╛ рдЙрдкрдпреЛрдЧ рдЯреЗрдореНрдкрд▓реЗрдЯ рдЗрдВрдЬрди рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкрд╛рд▓ рдХрдИ рдЕрд╕реНрдерд╛рдпреА рдЗрдВрдЬрдиреЛрдВ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЖрдк рдЗрд╕реЗ рдЕрдкрдиреЗ рдкрд╕рдВрджреАрджрд╛ рдореЗрдВ config / views.js рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ:

ejs, jade, handlebars, mustache

underscore, hogan, haml, haml-coffee, dust

atpl, eco, ect, jazz, jqtpl, JUST, liquor, QEJS,

swig, templayed, toffee, walrus, & whiskers









рдЪреЗрддрд╛рд╡рдиреА! 0.10 рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ, рд▓рд╛рдЗрд╡рдЖрдЙрдЯреНрд╕ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдХреЗрд╡рд▓ рдИрдЬреЗ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, рдПрдХ рдмреБрдирд┐рдпрд╛рджреА views/layout.ejs



ред views/layout.ejs



рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдЕрдиреНрдп рд╕рднреА views/layout.ejs



рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реЗ рд╣реИрдВред рдФрд░ рдЯреЗрдореНрдкрд▓реЗрдЯ рдЗрдВрдЬрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, ejs рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХреЛрдИ рд╡рд┐рд░рд╛рд╕рдд рдирд╣реАрдВ рд╣реЛрдЧреАред рдпрджрд┐ рдЖрдк рдЗрдВрдЬрди рд╡рд┐рдХрд▓реНрдк рдХреЛ config/views.js



рдореЗрдВ рдмрджрд▓рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ

 warn: Sails' built-in layout support only works with the `ejs` view engine. warn: You're using `hogan`. warn: Ignoring `sails.config.views.layout`...
      
      







рдЧреНрд░рд╛рд╣рдХ



рд╕рд░реНрд╡рд░ рддреИрдпрд╛рд░ рд╣реИ, рдЪрд▓рд┐рдП рд╣рдорд╛рд░реЗ рдЪрд╛рд▓рд╛рди рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдХреНрд▓рд╛рдЗрдВрдЯ рднрд╛рдЧ рдХреЛ рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред



рд╕реНрдереИрддрд┐рдХ рдХрдиреЗрдХреНрд╢рди


рд╕рднреА рд╕реНрдЯреЗрдЯрд┐рдХреНрд╕ (рдпрд╛ рдкрдмреНрд▓рд┐рдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛрдб) рдПрд╕реЗрдЯ рдлреЛрд▓реНрдбрд░ рдореЗрдВ рд╣реИрдВред рдЕрдкрдиреЗ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рдирдИ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдЙрдиреНрд╣реЗрдВ рдЙрдЪрд┐рдд рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд░рдЦреЗрдВ (рд╕рдВрдкрддреНрддрд┐ / рдЬреЗрдПрд╕ рдореЗрдВ рд╕реНрдХреНрд░рд┐рдкреНрдЯ, рдкрд░рд┐рд╕рдВрдкрддреНрддрд┐рдпреЛрдВ / рд╢реИрд▓рд┐рдпреЛрдВ рдореЗрдВ рд╢реИрд▓реА, рд╕рдВрдкрддреНрддрд┐ / рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рдЧреНрд░рд╛рд╣рдХ рдЯреЗрдореНрдкрд▓реЗрдЯ) рдФрд░ рдЙрдирдХреЗ рдЧреНрд░рдиреНрдЯ рдХрд╛рд░реНрдп рдХреЗ рд╕рд╛рде рдкрд╛рд▓ рдЙрдиреНрд╣реЗрдВ рдЖрдкрдХреЗ рд╕реВрдЪрдХрд╛рдВрдХ / рд▓реЗрдЖрдЙрдЯ рдореЗрдВ рд▓рд┐рдЦреЗрдВрдЧреЗред .ejs - рд╡рд┐рд╢реЗрд╖ рд╡рд░реНрдЧреЛрдВ рдореЗрдВ:

рд╕реНрд░реЛрдд рдлрд╝рд╛рдЗрд▓ / рд╕рд╛рдХреНрд╖рд╛рддреНрдХрд╛рд░ /layout.ejs рдХреА рд╕реВрдЪреА
  <!DOCTYPE html> <html> <head> <title>New Sails App</title> <!-- Viewport mobile tag for sensible mobile support --> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <!--STYLES--> <link rel="stylesheet" href="/styles/importer.css"> <!--STYLES END--> </head> <body> <%- body %> <!--TEMPLATES--> <!--TEMPLATES END--> <!--SCRIPTS--> <script src="/js/dependencies/sails.io.js"></script> <!--SCRIPTS END--> </body> </html>
      
      







рд╣рдо cdn рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдкрдиреЗ рд▓реЗрдЖрдЙрдЯ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ (Jquery, Underscore, Backbone, Ractive) рдХреЛ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВрдЧреЗ, рд╕рд╛рде рд╣реА bootstrap.min.css



app.css



рдФрд░ assets/styles



рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рддреИрдпрд╛рд░ app.css



рдлрд╝рд╛рдЗрд▓ app.css



ред рд╣рдо assets/js/vendor



рдлреЛрд▓реНрдбрд░ рдФрд░ assets/js



рдлреЛрд▓реНрдбрд░ рдореЗрдВ рдПрдХ рдЦрд╛рд▓реА app.js



рдлрд╛рдЗрд▓ рдХреЗ рд▓рд┐рдП рдЕрддрд┐рд░рд┐рдХреНрдд js рднреА рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВ, moment.ru.js



рдЖрдкрдХреЛ рдЬрд░реВрд░рдд рд╣реИ ( bootstrap.min.css



, moment.ru.js



and moment.min.js



- рддрд╛рд░реАрдЦреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА) assets/js



ред sails lift



рдФрд░ рджреЗрдЦреЗрдВ рдХрд┐ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдлрд╛рдЗрд▓ views/layout.ejs





рд╕реНрд░реЛрдд рдлрд╝рд╛рдЗрд▓ / рд╕рд╛рдХреНрд╖рд╛рддреНрдХрд╛рд░ /layout.ejs рдХреА рд╕реВрдЪреА
  <!DOCTYPE html> <html> <head> <title>New Sails App</title> <!-- Viewport mobile tag for sensible mobile support --> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <!--STYLES--> <link rel="stylesheet" href="/styles/app.css"> <link rel="stylesheet" href="/styles/bootstrap.min.css"> <link rel="stylesheet" href="/styles/importer.css"> <!--STYLES END--> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script> <script src="//cdn.ractivejs.org/latest/ractive.min.js"></script> <script src="//api.filepicker.io/v1/filepicker.js"></script </head> <body> <%- body %> <!--TEMPLATES--> <!--TEMPLATES END--> <!--SCRIPTS--> <script src="/js/dependencies/sails.io.js"></script> <script src="/js/app.js"></script> <script src="/js/vendor/bootstrap.min.js"></script> <script src="/js/vendor/moment.min.js"></script> <script src="/js/vendor/moment.ru.js"></script> <!--SCRIPTS END--> </body> </html>
      
      







рдорд╣рд╛рди, рдкрд╛рд▓ рдиреЗ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╕рдм рдХреБрдЫ рдХрд┐рдпрд╛ред рд╕рдЪ рд╣реИ, рдПрдХ рдорд╛рдЗрдирд╕ рд╣реИ - рд╡реЗрдВрдбрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╣рдорд╛рд░реЗ app рдХреЗ рдиреАрдЪреЗ рдЬреБрдбрд╝реЗ рд╣реБрдП рд╣реИрдВред рд╣рдо tasks/pipeline.js



рдлрд╝рд╛рдЗрд▓ рдХреЛ рдареАрдХ рдХрд░рддреЗ tasks/pipeline.js



рдпрд╣ рдмрддрд╛рддреЗ рд╣реИрдВ рдХрд┐ рд╡рд┐рдХреНрд░реЗрддрд╛ рдлрд╝реЛрд▓реНрдбрд░ рдХреЛ рдкрд╣рд▓реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП:

рдХрд╛рд░реНрдпреЛрдВ / рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдХреА рд╕реВрдЪреА рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ред рдЬреЗрдПрд╕ рдлрд╛рдЗрд▓
 ...... // CSS files to inject in order // // (if you're using LESS with the built-in default config, you'll want // to change `assets/styles/importer.less` instead.) var cssFilesToInject = [ 'styles/**/*.css' ]; // Client-side javascript files to inject in order // (uses Grunt-style wildcard/glob/splat expressions) var jsFilesToInject = [ // Dependencies like sails.io.js, jQuery, or Angular // are brought in here 'js/dependencies/**/*.js', 'js/vendor/**/*.js', //   vendor // All of the rest of your client-side js files // will be injected here in no particular order. 'js/**/*.js' ]; ........
      
      







рдХреНрд▓рд╛рдЗрдВрдЯ рднрд╛рдЧ рдХреА рддреИрдпрд╛рд░реА рдкреВрд░реА рд╣реЛ рдЧрдИ рд╣реИ - рд╣рдо рд╕реАрдзреЗ рдЖрд╡реЗрджрди рдХреЗ рд╡реНрдпрд╛рдкрд╛рд░ рддрд░реНрдХ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред



рдкреЗрдЬ рд▓реЗрдЖрдЙрдЯ рдХрдВрдХрд╛рд▓ рдмрдирд╛рдирд╛ред Ractive.js рдЯреЗрдореНрдкреНрд▓реЗрдЯ


рдЖрдЗрдП рдлрд┐рд░ рд╕реЗ рд╣рдорд╛рд░реЗ рд▓реЗрдЖрдЙрдЯ рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВред рдЗрд╕ рдкрд░, рдореИрдВрдиреЗ рдЙрди рдмреНрд▓реЙрдХреЛрдВ рдкрд░ рдкреНрд░рдХрд╛рд╢ рдбрд╛рд▓рд╛, рдЬрд┐рдиреНрд╣реЗрдВ рд╣рдо рдЕрдкрдиреЗ рдЧрддрд┐рд╢реАрд▓ рдбреЗрдЯрд╛ рд╕реЗ рдмрд╛рдВрдзреЗрдВрдЧреЗред



рдЪрд▓рд┐рдП рдлрд╛рдЗрд▓ рд╡реНрдпреВ / рдореЗрди / рдЬреЗрдирд░реЗрдЯ рдореЗрдВ рдмреБрдирд┐рдпрд╛рджреА рдорд╛рд░реНрдХрдЕрдк рдмрдирд╛рддреЗ рд╣реИрдВред рдЬреЗрдПрд╕ рдЬрд┐рд╕рдореЗрдВ рд╣рдорд╛рд░реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд╢рд╛рдорд┐рд▓ рд╣реЛрдВрдЧреЗ

рдлрд╝рд╛рдЗрд▓ рджреГрд╢реНрдп / рдореБрдЦреНрдп / рдЬрдирд░реЗрдЯрд┐рдВрдЧ рд╕реВрдЪреА
  <div class="main_bg"> <div class="container primary-content"> <div class="invoice-container rounded-container peel-shadows col-sm-8 col-sm-offset-2"> <h2 style="text-align:center;margin-bottom:30px;">  </h2> <div class="invheader"> <div class="invheader-upper"> <!-- User .       : , ,  --> </div> <div class="invheader-lower"> <!-- Invoice .            --> </div> </div> <div class="invbody"> <div class="invbody-tasks"> <!-- Task .        --> </div> <div class="clearb" style="height: 1px; overflow: hidden;"></div> <div class="invbody-account"> <!-- User  .        --> </div> </div> </div> </div> </div>
      
      









рддреЛ, рдореВрд▓ рдорд╛рд░реНрдХрдЕрдк рддреИрдпрд╛рд░ рд╣реИ - рдпрд╣ ractive.js рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХрд╛ рд╕рдордп рд╣реИ

рд╣рдорд╛рд░реЗ рдкреНрд░рддреНрдпреЗрдХ рдмреНрд▓реЙрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рдмрдирд╛рдПрдВ (рдХреБрд▓ рдореЗрдВ рдЪрд╛рд░ рд╣реЛрдВрдЧреЗ) рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╕рдВрдкрддреНрддрд┐ / рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рд░рдЦреЗрдВ

рд╕рдВрдкрддреНрддрд┐ / рдЯреЗрдореНрдкреНрд▓реЗрдЯ / рдЗрдирд╣рд┐рдбрд░-рдЕрдкрд░-html рдХреА рд╕реВрдЪреА
  <div class="invheader-address-account" on-hover="toggleBtn"> <a role="button" title="{{ .editing ? '' : ' ' }}" class="hidden-print btn btn-primary btn-sm hide" on-click="edit"><i class="glyphicon glyphicon-{{ .editing ? 'ok' : 'pencil' }}"></i> </a> <b>:</b> <div class="user-name {{ .editing ? 'editing' : '' }}"> <span>{{^name}} {{/name}}{{name}}</span> {{#.editing}} <div class='edit-container'> <input intro="select" value="{{name}}" class="form-control" placeholder="  "> </div> {{/.editing}} </div> <div class="user-address {{ .editing ? 'editing' : '' }}"> <span>{{^address}}  {{/address}}{{{address}}}</span> {{#.editing}} <div class='edit-container'> <textarea value="{{address}}" class='edit form-control' placeholder="  ">{{address}}</textarea> </div> {{/.editing}} </div> </div> <div on-hover="togglePicker" class="invheader-logo-container"> <div class="invheader-logo"> {{#avatar}} <img src="{{avatar}}/convert?h=110&w=250" alt="{{name}}"> {{/avatar}} <div class="hidden-print BoardCreateRep {{ avatar ? 'hide' : '' }}"> <input type="filepicker-dragdrop" data-fp-mimetype="image/png" data-fp-apikey="A3lXl09sRSejY4e0pOOSQz" data-fp-button-class="btn btn-primary hidden-print" data-fp-button-text=" " data-fp-drag-text="  " data-fp-drag-class="hidden-print drop-avatar" onchange="app.user.fire('setAvatar', event)"> </div> </div> </div>
      
      







рдкрд░рд┐рд╕рдВрдкрддреНрддрд┐рдпреЛрдВ / рдЯреЗрдореНрдкреНрд▓реЗрдЯ / рдЗрдирд╡реЙрд▓реНрдбрд░-рд▓реЛрдЕрд░.html рдХреА рд╕реВрдЪреА
  <div class="invheader-address-client" on-hover="toggleBtn"> <a role="button" title="{{ .editing ? '' : ' ' }}" class="hidden-print btn btn-primary btn-sm hide" on-click="edit"><i class="glyphicon glyphicon-{{ .editing ? 'ok' : 'pencil' }}"></i> </a> <b>:</b> <div class="cleint-name {{ .editing ? 'editing' : '' }}"> <span>{{^invoice.name}} {{/invoice.name}}{{invoice.name}}</span> {{#.editing}} <div class='edit-container'> <input intro="select" value="{{invoice.name}}" class="form-control" placeholder="   "> </div> {{/.editing}} </div> <div class="client-address {{ .editing ? 'editing' : '' }}"> <span>{{^invoice.address}}  {{/invoice.address}}{{{invoice.address}}}</span> {{#.editing}} <div class='edit-container'> <textarea value="{{invoice.address}}" class="edit form-control" placeholder="   ">{{invoice.address}}</textarea> </div> {{/.editing}} </div> </div> <div class="invheader-invoicedetails"> <table cellspacing="0"> <tbody> <tr> <th> </th> <td>#{{ lastFour(invoice.id) }}</td> </tr> <tr> <th>           </th> <td>{{ date(invoice.createdAt) }}</td> </tr> <tr class="invheader-invoicedetails-balance"> <th><div>             </div></th> <td><div> {{^invoice.total_amount}}0.00{{/invoice.total_amount}}{{ invoice.total_amount }}       </div></td> </tr> </tbody> </table> </div>
      
      







рд╕рдВрдкрддреНрддрд┐ / рдЯреЗрдореНрдкреНрд▓реЗрдЯ / рдЗрдирд╡реЙрдЗрд╕-рдЯрд╛рд╕реНрдХ.html рдХреА рд╕реВрдЪреА
  <table class="invbody-items" cellspacing="0"> <thead> <tr> <th class="first"><div class="item">      </div></th> <th><div class="description">,        </div></th> <th><div class="unitcost"> ()</div></th> <th><div class="quantity">      </div></th> <th class="last"><div class="linetotal"> ()</div></th> </tr> </thead> <tbody> {{#tasks}} <tr> <td style="width: 160px;"> <a on-tap="destroy:{{this}}" role="button" class='hidden-print destroy'></a> <div on-click="edit" class="item">{{name}}</div> <input intro="select" class="form-control hide" value="{{name}}" on-blur-enter="hide:{{this}}"> </td> <td> <div on-click="edit" class="description">{{description}}</div> <textarea class="form-control hide" value="{{description}}" on-blur-enter="hide:{{this}}">{{description}}</textarea> </td> <td style="width: 85px;"> <div on-click="edit" class="unitcost">{{ format(rate) }}</div> <input class="form-control hide" value="{{rate}}" on-blur-enter="hide:{{this}}"> </td> <td style="width: 80px;"> <div on-click="edit" class="quantity">{{ format(hours) }}</div> <input class="form-control hide" value="{{hours}}" on-blur-enter="hide:{{this}}"> </td> <td style="width: 90px;"> <div class="linetotal">{{ format(rate * hours) }}</div> </td> </tr> {{/tasks}} <tr> <td class="hidden-print text-center" colspan="5"> <button on-click="add" class="btn btn-primary btn-sm"><i class="glyphicon glyphicon-plus "></i> </button> </td> </tr> </tbody> </table> <table class="invbody-summary" cellspacing="0"> <tbody> <tr> <td class="invbody-summary-clean"> </td> <td style="width: 150px;"><strong> :    </strong></td> <td style="width: 120px;"><strong> {{ total(tasks) }} </strong></td> </tr> <tr class="invbody-summary-paid"> <td class="invbody-summary-clean"> </td> <td style="width: 150px;">    </td> <td style="width: 120px;">-0.00</td> </tr> <tr class="invbody-summary-total"> <td class="invbody-summary-clean"> </td> <td style="width: 150px;"><div><strong>  :    </strong></div></td> <td style="width: 120px;"><div><strong> {{ total(tasks) }} </strong></div></td> </tr> </tbody> </table>
      
      







рд╕рдВрдкрддреНрддрд┐ / рдЯреЗрдореНрдкреНрд▓реЗрдЯ / рдЗрдирд╡реЙрдЗрд╕-рдЕрдХрд╛рдЙрдВрдЯ.html рдХреА рд╕реВрдЪреА
  <div class="invbody-terms" on-hover="toggleBtn"> <a role="button" title="{{ .editing ? '' : ' ' }}" class="hidden-print btn btn-primary btn-sm hide" on-click="edit"><i class="glyphicon glyphicon-{{ .editing ? 'ok' : 'pencil' }}"></i> </a> <b>:</b> <div class="user-account {{ .editing ? 'editing' : '' }}"> <span>{{^account}}  {{/account}}{{{account}}}</span> {{#.editing}} <div class='edit-container'> <textarea value="{{account}}" class='edit form-control' placeholder="    ">{{account}}</textarea> </div> {{/.editing}} </div> </div>
      
      







рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрд╣ рдПрдХ рдирд┐рдпрдорд┐рдд HTML рд╣реИ, рдЬреЛ рдореВрдВрдЫреЛрдВ рд╡рд╛рд▓реЗ рдЯреИрдЧ {{}}



рд╕реЗ рдЗрдВрдЯрд░рд╕реЗрдкреНрдЯреЗрдб рд╣реИ , рдЬрд┐рд╕рдореЗрдВ ractive.js рдЕрдкрдирд╛ рдбреЗрдЯрд╛ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЖрдк рдХреБрдЫ рдирд┐рд░реНрджреЗрд╢реЛрдВ on-click="edit"



рднреА on-click="edit"



- рдпрд╣ рдХреНрд▓рд┐рдХ рджреНрд╡рд╛рд░рд╛ edit



рд╡рд┐рдзрд┐ рдХреЛ рдХреНрд░рд┐рдпрд╛рдиреНрд╡рд┐рдд рдХрд░рддрд╛ рд╣реИ; on-hover="toggleBtn"



, on-tap="destroy:{{this}}"



рдмрд╛рдж рдореЗрдВ рдЗрд╕ рдмрд┐рдВрджреБ on-tap="destroy:{{this}}"



рдХрд╡рд░ on-tap="destroy:{{this}}"



, рдЕрдм рд╣рдо ractive.js рдШрдЯрдирд╛рдУрдВ рдкрд░ рдбреЙрдХреНрдЯрд░ рдХреА рдЬрд╛рдВрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ



рдШрдЯрдирд╛рдХреНрд░рдо рдкреНрд▓рдЧрдЗрдиреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдХреНрд░рд┐рдп рдореЗрдВ рдЬреБрдбрд╝реЗ рд╣реБрдП рд╣реИрдВ - рддрдерд╛рдХрдерд┐рдд рдкреНрд░реЙрдХреНрд╕реА-рдЗрд╡реЗрдВрдЯред рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдЬрд┐рдирдХреА рд╣рдореЗрдВ рдЬрд╝рд░реВрд░рдд рд╣реИ (рдореИрдВрдиреЗ рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рднреА рдкреНрд▓рдЧрдЗрдиреНрд╕ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдП рд╣реИрдВ) рдФрд░ рдЙрдиреНрд╣реЗрдВ assets/js/vendor



рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд░рдЦреЗрдВ

рдмреИрдХрдмреЛрди рдХреЗ рд▓рд┐рдП рдПрдбрд╛рдкреНрдЯрд░ рдХреЛ рдЙрд╕реА рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд░рдЦреЗрдВ рддрд╛рдХрд┐ ractive.js рдбреЗрдЯрд╛ рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рдмреИрдХрдмреЛрди рдореЙрдбрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХреЗрдВред



рдбреЗрдЯрд╛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝реЗрд╢рдиред рдбреЗрдЯрд╛ рдФрд░ рдЯреЗрдореНрдкрд▓реЗрдЯ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ


рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдмрддрд╛рдПрдВ рдХрд┐ рдЗрд╕ рд╕рдордп рдХреНрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рд╣рдо рдХреНрдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ





рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдорд╛рд░реА рдЦрд╛рд▓реА assets/js/app.js



рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдмреИрдХрдмреЛрди рдореЙрдбрд▓ assets/js/app.js



:

рд▓рд┐рд╕реНрдЯрд┐рдВрдЧ рд╕рдВрдкрддреНрддрд┐ / рдЬреЗ рдПрд╕ / app.js
 var app = app || {}; (function (app) { app.User = Backbone.Model.extend({ urlRoot: '/user', }); app.Invoice = Backbone.Model.extend({ urlRoot: '/invoice', }); app.Task = Backbone.Model.extend({ urlRoot: '/task', }); app.Tasks = Backbone.Collection.extend({ url: '/task', model: app.Task }); })(app);
      
      







рдареАрдХ рд╣реИ, рдЕрдм рд╣рдо рдПрдХ рд╕рдХреНрд░рд┐рдп рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ рд╣рдорд╛рд░реЗ app.User рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП рдмрд╛рдзреНрдп рд╣реЛрдЧрд╛ рдФрд░ рд╣рдорд╛рд░реА assets/templates/invheader-upper.html



рдФрд░ assets/templates/invbody-account.html



рд░реЗрдВрдбрд░ рдХрд░реЗрдЧрд╛

рд╕рдВрдкрддреНрддрд┐ / js / user.js рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ

рд╕реВрдЪреАрдмрджреНрдз рд╕рдВрдкрддреНрддрд┐ / рдЬреЗрдПрд╕ / user.js
 var app = app || {}; (function (app) { var backboneUser = new app.User; //    ractive   Ractive.extend //  new Ractive({}),      2   var RactiveUser = Ractive.extend({ init: function (options) { this.data = options.data; this.on({ //      //   `on-click="edit"` edit: function (event) { var editing = this.get('editing'); this.set( 'editing', !editing ); if (editing) { this.data.save(); //     } }, //       //  https://www.inkfilepicker.com //   `onchange="app.user.fire('setAvatar', event)"` setAvatar: function (event) { if (event.fpfile) { var url = event.fpfile.url; this.set('avatar', url); } else { this.set('avatar', null); } this.data.save(); //     }, //        //   `on-hover="togglePicker"` togglePicker: function (event) { if (!this.get('avatar')) return; if ( event.hover ) { $(event.node).find('.BoardCreateRep').removeClass('hide'); } else { $(event.node).find('.BoardCreateRep').addClass('hide'); } }, //        //   `on-hover="toggleBtn"` toggleBtn: function (event) { if ( event.hover ) { $(event.node).find('[role=button]').removeClass('hide'); } else { $(event.node).find('[role=button]').addClass('hide'); } } }); } }); //  RactiveUser    //      `.invheader-upper` app.user = new RactiveUser({ el: '.invheader-upper', template: JST['assets/templates/invheader-upper.html'](), data: backboneUser, adaptors: [ 'Backbone' ], }); //  RactiveUser    //      `.invheader-account` app.account = new RactiveUser({ el: '.invbody-account', template: JST['assets/templates/invbody-account.html'](), data: backboneUser, adaptors: [ 'Backbone' ], }); //    Id  //  id  (   ) //      app.user.observe('id', function(id){ if (id && app.invoice) { app.invoice.data.invoice.set('owner', id); app.invoice.data.invoice.save(); } }); })(app);
      
      







рдХреЛрдб рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред рдпрд╣рд╛рдБ рд╣рдо рдмреЗрд╕ рдХреНрд▓рд╛рд╕ RactiveUser



ред рдЖрдк рдЖрдорддреМрд░ рдкрд░ new Ractive({})



рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдпрд╣рд╛рдВ рд╣рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП 2 рддрддреНрд╡реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ рдЬреЛ рдПрдХ рд╣реА рдореЙрдбрд▓ рд╕реЗ рдЬреБрдбрд╝реЗ рд╣реЛрддреЗ рд╣реИрдВ рдФрд░ рдЬреЛ рд▓рдЧрднрдЧ рдПрдХ рд╣реА рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдШрдЯрдирд╛рдУрдВ рдХреЛ рд╕реНрд╡рдпрдВ init



рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред



рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реБрдП, рд╣рдо рд╕рд╛рджреГрд╢реНрдп assets/js/task.js



рдФрд░ assets/js/task.js





рд╕реВрдЪреАрдмрджреНрдз рд╕рдВрдкрддреНрддрд┐ / рдЬреЗрдПрд╕ / рдЗрдирд╡реЙрдЗрд╕.рдЬреЗрдПрд╕
 var app = app || {}; (function (app) { app.invoice = new Ractive({ el: '.invheader-lower', template: JST['assets/templates/invheader-lower.html'](), data: { invoice: new app.Invoice, //  Backbone  //        {{ date(createdAt) }} date: function (date) { return moment(date).format('D MMMM YYYY'); }, //    {{ lastFour(id) }} lastFour: function (str) { return str.slice(-4); } }, adaptors: [ 'Backbone' ], transitions: { select: function ( t ) { setTimeout( function () { t.node.select(); t.complete(); }, 200 ); } } }); app.invoice.on({ //      //   `on-click="edit"` edit: function (event) { console.log(event); var editing = this.get('editing'); this.set( 'editing', !editing ); if (editing) { this.data.invoice.save({owner: app.user.data.id}); } }, //        //   `on-hover="toggleBtn"` toggleBtn: function (event) { if ( event.hover ) { $(event.node).find('[role=button]').removeClass('hide'); } else { $(event.node).find('[role=button]').addClass('hide'); } } }); //      app.invoice.data.invoice.save(); })(app);
      
      







рд╕рдВрдкрддреНрддрд┐ / js / task.js рдХреЛ рд╕реВрдЪреАрдмрджреНрдз рдХрд░рдирд╛
 var app = app || {}; (function (app) { app.tasks = new Ractive({ el: '.invbody-tasks', template: JST['assets/templates/invbody-tasks.html'](), data: { tasks: new app.Tasks, //  Backbone  //     {{ format(price) }} format: function ( num ) { return num.toFixed( 2 ); }, //     {{ total(tasks) }} total: function ( collection ) { var total = collection.reduce(function( sum, el ) { return el.get('rate') * el.get('hours') + sum; }, 0 ); return total.toFixed( 2 ); }, }, adaptors: [ 'Backbone' ], transitions: { select: function ( t ) { setTimeout( function () { t.node.select(); t.complete(); }, 200 ); } } }); app.tasks.on({ //       //   `on-click="add"` add: function ( event ) { var tasks = this.get('tasks'); var task = new app.Task({ name: ' ', description: ' ', hours: 0, rate: 0, }); tasks.add(task); task.save(null, { // ,         success: function() { task.set('invoice', app.invoice.data.invoice.id); task.save(); } }); }, //      //   `on-tap="destroy:{{this}}"` destroy: function ( event, task ) { task.destroy(); }, //       //   `on-click="edit"` edit: function ( event ) { $(event.node).hide(); $(event.node).next().removeClass('hide').focus().select(); }, //     -  //   `on-blur-enter="hide"` hide: function ( event, task ) { $(event.node).addClass('hide'); $(event.node).prev().show(); task.save({invoice: app.invoice.data.invoice.id}); }, }); //     `hours`  `rate`   //    //      // TODO       app.tasks.observe('tasks.*.hours tasks.*.rate', function(tasks, old, keypath){ var total = this.data.total(this.data.tasks); app.invoice.data.invoice.set('total_amount', total); }); })(app);
      
      







рдпрд╣рд╛рдВ, рдХреЛрдб рдкрд░реНрдпрд╛рдкреНрдд рд╕реНрдкрд╖реНрдЯ рд╣реИ, рдШрдЯрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЯрд┐рдкреНрдкрдгреА рдЬреЛрдбрд╝ рджреА рдЧрдИ рд╣реИред рдпрд╣ рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рд╕рднреА рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛрдб рд╣реИред рдореИрдВрдиреЗ id рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рд╕реНрдерд┐рд░ рдЪрд╛рд▓рд╛рди рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рдзрд┐ рдХреЛ рддреЗрдЬ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рдИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, localhost:1337/main/generate/535ea7aa6113230d773fd160



localhost:1337/main/generate/535ea7aa6113230d773fd160



) рдпрд╛ api pdfcrowd.com рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ, рд╕реМрднрд╛рдЧреНрдп рд╕реЗ рдЙрдирдХреЗ рдкрд╛рд╕ рдиреЛрдб рдХреЗ рд▓рд┐рдП рдПрдХ рдореЙрдбреНрдпреВрд▓ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ url рджреНрд╡рд╛рд░рд╛ рдкреАрдбреАрдПрдл рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ ... рд╣рд╛рд▓рд╛рдВрдХрд┐, рдореИрдВрдиреЗ рд╕рдкреНрддрд╛рд╣рд╛рдВрдд рдкрд░ рдРрд╕рд╛ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдирд╣реАрдВ рдХрд┐рдпрд╛ред рдЕрдм рдореИрдВ ctrp + P (рдкреНрд░рд┐рдВрдЯ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП) -> "рдкреНрд░рд┐рдВрдЯ рдЯреВ рдлрд╛рдЗрд▓" рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреАрдбреАрдПрдл рдмрдирд╛ рд░рд╣рд╛ рд╣реВрдВред рдФрд░ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдПрдЪрдЯреАрдПрдордПрд▓ рддрддреНрд╡реЛрдВ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдмрдЯрди) рд╕реЗ рдмрд╛рд╣рд░ рди рдирд┐рдХрд▓рдиреЗ рдХреЗ рд▓рд┐рдП - рдЙрдирдХреЗ рд▓рд┐рдП рдПрдХ hidden-print



рдХреНрд▓рд╛рд╕ рдЬреЛрдбрд╝рд╛ред



рд╕рд░реНрд╡рд░ рдкрд░ рддреИрдирд╛рдд рдХрд░реЗрдВ


рдпрд╣ рд▓рдЧрднрдЧ рд╕рднреА рд╣реИ - рдЖрд╡реЗрджрди рддреИрдпрд╛рд░ рд╣реИред рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдЧрд┐рддреБрдм рдкрд░ рд╣реИ



рд╕рд░реНрд╡рд░ рдкрд░, рд╣рдо рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЛ рдХреНрд▓реЛрди рдХрд░рддреЗ рд╣реИрдВ, рдирд┐рд░реНрднрд░рддрд╛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрддреНрдкрд╛рджрди рдореЛрдб рдореЗрдВ рдкрд╛рд▓ рдЪрд▓рд╛рддреЗ рд╣реИрдВ:

 node app.js --port=8000 --prod
      
      







рдЙрддреНрдкрд╛рджрди рдореЛрдб рдореЗрдВ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдбреЗрдореЛ рдХреЛ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛



рд╕рд╛рд░рд╛рдВрд╢



рд╕реЗрд▓реНрдЬ рдФрд░ рдПрдХреНрдЯрд┐рд╡ рджреЛрдиреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдмрд╣реБрдд рдкреНрд░рд╕рдиреНрди рдерд╛ред

Selsjs - рдкреЗрд╢реЗрд╡рд░реЛрдВ:

+ рдкрд╕рдВрдж рдХрд┐рдпрд╛ рдЧрдпрд╛ рдХрд┐ рдХреИрд╕реЗ рдЖрд╕рд╛рди рдПрдкреАрдЖрдИ рдореЗрдВ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ

+ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╡рд┐рдиреНрдпрд╛рд╕ рд╡рд┐рдХрд▓реНрдк, рдЯреЗрдореНрдкрд▓реЗрдЯ рдЗрдВрдЬрди, рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ ORM рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдореИрдВ sails рдХреЗ рд▓рд┐рдП bookhelfjs.org рдкреЗрдВрдЪ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд░рд╣рд╛ рд╣реВрдВ)

+ рдореБрдЭреЗ рдмрд╣реБрдд рдкрд╕рдВрдж рдЖрдпрд╛ рдХрд┐ рдРрд╕реЗ рддреИрдпрд╛рд░ рдХрд┐рдП рдЧрдП рдЧреНрд░рдиреНрдЯ рдХрд╛рд░реНрдп рд╣реИрдВ рдЬреЛ рджреЛрдиреЛрдВ рдареЗрд╕ рдФрд░ рдиреМрдХрд░рд╛рдиреА рдмрдВрдбрд▓реЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХрд╛ рдПрдХ рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВред

+ рдПрдХ рдХрдорд╛рдВрдб ( sails www



) рд╣реИ рдЬреЛ рдХреЗрд╡рд▓ рдХреНрд▓рд╛рдЗрдВрдЯ-рд╕рд╛рдЗрдб рдХреЛрдб рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИ - рд╕рд╛рдордиреЗ рдФрд░ рд╕рд░реНрд╡рд░ рд╕рдВрдЪрд╛рд▓рди рдХреЛ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред

+ рдмрд╣реБрднрд╛рд╖реА рд╕рдорд░реНрдерди (рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИ)



рд╡рд┐рдкрдХреНрд╖:

- рдлрд┐рд▓рд╣рд╛рд▓, рдореЙрдбрд▓ рдХреА рдЕрд╕рд╛рд╡рдзрд╛рдирд┐рдпреЛрдВ рдХрд╛ рдЫреЛрдЯрд╛ рдХрд╛рдо (рдореИрдВ рд╕рдордЭрддрд╛ рд╣реВрдВ рдХрд┐ v0.10 рдЕрднреА рднреА рдмреАрдЯрд╛ рд╣реИ, рд▓реЗрдХрд┐рди v0.9.x рдореЗрдВ рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рднреА рдирд╣реАрдВ рд╣реИ)

- рдХреЗрд╡рд▓ рд▓реЗрдЖрдЙрдЯ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди ejs рдЯреЗрдореНрдкрд▓реЗрдЯреНрд╕



Ractivejs - pluses -

+ рдмреИрдХрдмреЛрди

+ рдПрдХреНрд╕реНрдЯреЗрдВрд╕рд┐рдмрд┐рд▓рд┐рдЯреА рдХреЛ рдмрд╛рдВрдзрдиреЗ рдХреА рдХреНрд╖рдорддрд╛ () рдЖрдк рдЕрдкрдиреЗ рдЦреБрдж рдХреЗ рдкреНрд▓рдЧрдЗрдиреНрд╕ рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВ)

+ рдореВрдВрдЫреЛрдВ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдЯреЗрдореНрдкрд▓реЗрдЯ рдЗрдВрдЬрди (рдореИрдВ рдИрдЬреЗрдПрд╕ рдХреА рддрд░рд╣ рдирд╣реАрдВ рд╣реВрдВ - рдпрд╣ рдореЗрд░реЗ рд▓рд┐рдП рдмрд╣реБрдд рднрд╛рд░реА рд╣реИ)

+ рдЕрдЪреНрдЫрд╛ рдбреЙрдХ, рдЙрджрд╛рд╣рд░рдг рдФрд░ рд╕рдХреНрд░рд┐рдп рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓



- рдореИрдВрдиреЗ рдХрдИ рджрд┐рдиреЛрдВ рдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рднреА рд╡рд┐рдкрдХреНрд╖ рдирд╣реАрдВ рдкрд╛рдпрд╛ред



рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред



All Articles