PageRenderTime 231ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/app/bookmarks_app.js

https://github.com/polinom/etv-bookmarks
JavaScript | 681 lines | 495 code | 155 blank | 31 comment | 49 complexity | e323ba83561ac3ec713291046b41cf8e MD5 | raw file
  1. etv.utils = {};
  2. etv.utils.slice = function(text,p){ if(text.length>=p){return text.slice(0,p)+"..."} else {return text} };
  3. etv.utils.error_message = function(message){jAlert("<h3 style='color:red;'>"+message+"</h3>", {title:"tiletile"})};
  4. etv.utils.info_message = function(message){jAlert("<h3 style='color:blue;'>"+message+"</h3>", {title:"tiletile"})};
  5. etv.utils.dialog_message = function(question, callback){ jConfirm("<h3 style='color:blue;'>"+question+"</h3>", 'Подтвердите Действие!', callback) }
  6. //------------------ BACKBONE SYNC -----------------------------------
  7. // var original_sync = Backbone.sync
  8. // Backbone.sync = function () {
  9. // console.log('sync started')
  10. // console.log(arguments)
  11. // arguments[2].success = function(){
  12. // console.log('sync finished')
  13. // }
  14. // original_sync.apply(Backbone, arguments);
  15. // };
  16. //---------------------------------------------------------------------
  17. //---------------------- MODELS -------------------------------------
  18. //---------------------------------------------------------------------
  19. etv.vid.bmark.Rubric = Backbone.Model.extend({
  20. urlRoot: '/api/v3.0/media/lists/rubrics/',
  21. })
  22. // Folder Item
  23. etv.vid.bmark.Entry = Backbone.Model.extend({
  24. urlRoot: '/api/v3.0/media/lists/',
  25. url: function(){
  26. return this.urlRoot+this.get('playlist').id+'/entries/'+this.get('id')+'/'
  27. },
  28. media_url: function(){
  29. return '/watch/'+this.get('media').id+'/'
  30. }
  31. });
  32. // Folder model
  33. etv.vid.bmark.Folder = Backbone.Model.extend({
  34. defaults: {
  35. 'image_path':'http://aux.iconpedia.net/uploads/196917932.png',
  36. 'title':'Default Folder Name',
  37. 'description':'Default Folder Description',
  38. 'duration':0,
  39. 'items':0,
  40. 'shared':0,
  41. "mark_total": 0,
  42. "mark_count": 0,
  43. 'id':null,
  44. 'rubric_verbose':'Нет Рубрики',
  45. },
  46. initialize: function(attrs, options) {
  47. this.children = new etv.vid.bmark.Entries([],{parent_model:this});
  48. Backbone.Model.prototype.initialize.call(this, attrs, options);
  49. },
  50. url: function(){
  51. if (this.get('id') == undefined) {
  52. return '/api/v3.0/media/lists/'
  53. }
  54. else {
  55. return '/api/v3.0/media/lists/'+this.get('id')+'/'
  56. }
  57. },
  58. validate: function(attrs) {
  59. if (typeof attrs.description == 'string' && attrs.description.length === 0) {
  60. if(attrs.description.length <= 1) return "Напишите описания к папке!";
  61. }
  62. if (typeof attrs.title == 'string' && attrs.title.length === 0) {
  63. if(attrs.title.length <= 1) return "Назовите папку!";
  64. }
  65. },
  66. set: function(attrs, options){
  67. if (attrs['description']){
  68. this.set( {'desc_short': etv.utils.slice( attrs['description'], 300 )} )
  69. }
  70. if (attrs['title']){
  71. this.set( { 'title_short': etv.utils.slice( attrs['title'], 20 )} )
  72. }
  73. return Backbone.Model.prototype.set.call(this, attrs, options);
  74. },
  75. });
  76. // Empty model for AppView
  77. etv.vid.bmark.AppModel = Backbone.Model.extend({})
  78. // - - - - - - - - - - - - - - -- - - - -- - - - - -- - - -- - - - -- -
  79. //---------------------- COLLECTIONS --------------------------------
  80. // - - - - -- - - - -- - -- - - - - -- - - - -- - - - - -- - - - - - -
  81. etv.vid.bmark.FolderRubric = Backbone.Collection.extend({
  82. model: etv.vid.bmark.Rubric,
  83. url: '/api/v3.0/media/lists/rubrics/'
  84. })
  85. // Items Collection
  86. etv.vid.bmark.Entries = Backbone.Collection.extend({
  87. initialize: function(list,options) {
  88. this.parent_model = options.parent_model;
  89. },
  90. model: etv.vid.bmark.Entry,
  91. // to change
  92. url: function(){
  93. return '/api/v3.0/media/lists/'+this.parent_model.get('id')+'/entries/'
  94. },
  95. empty: function(){
  96. $.ajax({ type: "DELETE", url: this.url() })
  97. }
  98. });
  99. // Folder Collection
  100. etv.vid.bmark.Folders = Backbone.Collection.extend({
  101. model: etv.vid.bmark.Folder,
  102. url: '/api/v3.0/media/lists?ptype=1',
  103. });
  104. // - - -- - - -- - - -- - - -- - - - -- - - - - -- - - -- - - - -- - -
  105. //---------------------- VIEWS --------------------------------------
  106. // - - - - -- - - - -- - -- - - - - -- - - - -- - - - - -- - - - - - -
  107. //Base View class with common methods to extend in future views
  108. etv.vid.bmark.BaseView = Backbone.View.extend({
  109. childrenClassName: 'child_container',
  110. initialize: function(attrs, options){
  111. _.bindAll(this, 'starsCallback', 'resortOnServer')
  112. this.children_views = []
  113. this.el = $(this.el)
  114. this.children_container = $(this.make("div", {'class': this.childrenClassName}))
  115. this.children = new this.collection_class([],{'parent_model':this.model})
  116. this.children.bind('reset', this.addAll, this);
  117. this.children.bind('add', this.addOne, this);
  118. this.model.bind('destroy', this.remove, this);
  119. },
  120. addOne: function(model){
  121. var self = this
  122. var children_view = new this.childrens_view({model: model, parent_view:this})
  123. this.children_views.push(children_view)
  124. $(this.children_container).prepend(children_view.render().el)
  125. },
  126. addAll: function(){
  127. var self = this
  128. this.children.each(this.addOne, this)
  129. this.el.find('.entries_container').append(this.children_container)
  130. etv.common.Fivestar.initialize(".fivestar",{ oneTimeOnly: true,
  131. active: false,
  132. success: function(res){
  133. self.starsCallback(self, res)
  134. }
  135. })
  136. this.el.find('.scroll_fave').sortable({ handle: '.arrows', update: this.resortOnServer })
  137. },
  138. resortOnServer: function(event, ui){
  139. var id = $(ui.item).attr('id')
  140. var index = $(ui.item).index() + 1
  141. model = this.children.get(id)
  142. model.set({'order':index})
  143. model.save()
  144. },
  145. starsCallback:function(self, res){
  146. self.model.set({mark_total: res.total, mark_count: res.count})
  147. },
  148. //this method uses only perent
  149. render: function(){
  150. $(this.el).html(this.template(this.model.toJSON()))
  151. return this
  152. }
  153. });
  154. // Single Entry view
  155. etv.vid.bmark.EntryView = etv.vid.bmark.BaseView.extend({
  156. tagName: "div",
  157. className: "children_container_small",
  158. template: _.template(this.$('#item_template').html()),
  159. menu_template: _.template(this.$('#menu_template').html()),
  160. events: {
  161. 'click .item_remove': 'removeItem',
  162. 'click .folders': 'moveItemButton',
  163. 'click .play_button': 'getMediaLink'
  164. },
  165. initialize: function(){
  166. _.bindAll(this, 'renderMenu','moveItem')
  167. this.el = $(this.el)
  168. etv.vid.bmark.Entries.bind('reset', this.addAll, this);
  169. this.model.bind('remove', this.remove, this)
  170. this.el.attr('id', this.model.get('id'))
  171. },
  172. getMediaLink: function(e){
  173. e.preventDefault()
  174. var self = this
  175. var data = {sl:'', bitrate:1}
  176. $.ajax({
  177. data: data,
  178. url: this.model.media_url(),
  179. type: "POST",
  180. dataType: 'json',
  181. success: function(resp){ self.playMedia(self,resp) }
  182. })
  183. },
  184. playMedia: function(self, resp){
  185. console.log(typeof etv.common.readCookie('Playinsilverlightcheckbox'))
  186. new etv.vid.play.Player({
  187. instanceUrl: 'http://static.etvnet.com/silverlight/OVP.xap',
  188. mediaUrl: resp.url,
  189. autoPlay: true,
  190. width: '540px',
  191. height: '481px',
  192. customParams : 'theme='+ 'http://static.etvnet.com/' + 'silverlight/themes/SmoothHD.xaml, stretchmode=Fit, stretchmodefullscreen=Fit, nologo=1',
  193. divId: 'SilverLight',
  194. errorMsg: "options.errorMsg"
  195. });
  196. if(etv.common.readCookie('Playinsilverlightcheckbox')==='true') {
  197. $('#SilverLight').dialog({position: ['center',100], modal:true, width: '570px',title: this.model.get('media').name, beforeclose: function(event, ui) {$('#SilverLight').empty(); $('#SilverLight').dialog('destroy'); }});
  198. } else {
  199. location.href = resp.url
  200. }
  201. },
  202. removeItem: function(e){
  203. e.preventDefault();
  204. this.model.destroy();
  205. this.el.slideUp('slow', function(){this.remove})
  206. items = this.options.parent_view.model.get('items') - 1
  207. duration = this.options.parent_view.model.get('duration') - this.model.get('media').duration
  208. this.options.parent_view.model.set({'items': items, 'duration': duration })
  209. //this.options.parent_view.model.set({'duration': duration})
  210. },
  211. moveItemButton: function(e){
  212. e.preventDefault()
  213. if (!this.menu_opend){ this.openMenu() }
  214. else { this.closeMenu() }
  215. },
  216. openMenu: function(){
  217. this.menu_opend = true
  218. this.renderMenu()
  219. },
  220. closeMenu: function(){
  221. this.menu_opend = false
  222. this.menu.remove()
  223. },
  224. renderMenu: function(e){
  225. var self = this
  226. var folders = this.options.parent_view.options.parent_view.children.toJSON()
  227. var html_folders = this.menu_template({'folders': folders})
  228. this.el.find('.folders').parent().append(html_folders);
  229. this.menu = this.el.find('.drop_fave')
  230. this.menu.find('.folder_add').live('click', function(e) { e.preventDefault(); self.moveItem(e,$(this));})
  231. },
  232. moveItem: function(e,link){
  233. var id = link.attr('id').replace('id_','')
  234. this.removeItem(e)
  235. var folder = this.options.parent_view.options.parent_view.children.get(parseInt(id))
  236. var items = folder.get('items') + 1
  237. var duration = folder.get('duration') + this.model.get('media').duration
  238. var image = this.model.get('image_path')
  239. folder.set( {items:items, duration:duration, image_path: image} )
  240. var url = folder.url()+'entries/'+this.model.get('media').id+'/'
  241. $.ajax({ data: {},
  242. type: 'POST',
  243. contentType: 'application/x-www-form-urlencoded',
  244. url: url,
  245. success: function(resp,status){console.log(resp)}
  246. })
  247. }
  248. });
  249. //Single folder view
  250. etv.vid.bmark.FolderView = etv.vid.bmark.BaseView.extend({
  251. empty_folder_image_url: 'http://aux.iconpedia.net/uploads/196917932.png',
  252. slideSpeed: 'slow',
  253. edit_mod: false,
  254. opend: false,
  255. childrenClassName: 'scroll_fave',
  256. collection_class: etv.vid.bmark.Entries,
  257. childrens_view: etv.vid.bmark.EntryView,
  258. tagName: "div",
  259. className: "etv-app-folder",
  260. template: _.template(this.$('#folder_template').html()),
  261. events: {
  262. "click .open, .close, .poster_a": "folderToggle",
  263. "click .folder_remove": "removeFolder",
  264. "click .save_edit_title" : 'toggleEditModTitle',
  265. "click .save_edit_desc" : 'toggleEditModDesc',
  266. "click .empty" : 'emptyFolder',
  267. "click .save_edit_rubric" : 'toggleEditModRubric',
  268. },
  269. confirm_shared_message: function() {
  270. var desc = this.model.get('description')
  271. if (desc.length === 3){
  272. desc = this.default_description()
  273. }
  274. return 'Папка «'+this.model.get('title')+'» с описанием «'+ desc +'» из раздела «'+this.model.get('rubric_verbose')+'» будет доступна другим зрителям eTVnet'
  275. },
  276. default_description: function() {
  277. if (this.children.length === 0) this.children.fetch()
  278. var desc = "В данной папке собраны фильмы и передачи из следующих разделов: "
  279. this.children.each(function(item){
  280. console.log(item)
  281. })
  282. return desc
  283. },
  284. emptyFolder: function(e) {
  285. etv.utils.dialog_message("OPOPOPOPOP", function(r){console.log(r)});
  286. e.preventDefault()
  287. this.children.empty()
  288. this.closeFolder()
  289. this.model.set({'items':0,'duration':0})
  290. },
  291. initialize: function(attributes,options){
  292. etv.vid.bmark.BaseView.prototype.initialize.call(this, attributes, options);
  293. this.children_container.css({height:'0px;'})
  294. _.bindAll(this, 'sharedChanged', 'confirmSharedChanged', 'openFolder', 'closeFolder', 'showLoader', 'hideLoader')
  295. this.model.bind("error", this.handleValidationError)
  296. this.model.bind("change:shared", this.shared_changed, this)
  297. this.model.bind("change:title", this.titleChanged, this)
  298. this.model.bind("change:description", this.descChanged, this)
  299. this.model.bind("change:items", this.itemsChanged, this)
  300. this.model.bind("change:duration", this.durationChanged, this)
  301. this.model.bind("change:id", this.idChanged, this)
  302. this.model.bind("change:mark_count", this.mark_count_changed, this)
  303. this.model.bind("change:image_path", this.image_path_changed, this)
  304. },
  305. showLoader: function(){
  306. this.el.find('.app_loader').show()
  307. },
  308. hideLoader: function(){
  309. this.el.find('.app_loader').hide()
  310. },
  311. toggleEditModRubric: function(e){
  312. e.preventDefault()
  313. if (this.rubric_edit_mod) {
  314. this.rubricTurnOffEditMod()
  315. } else {
  316. this.rubricTurnEditMod()
  317. }
  318. },
  319. rubricTurnEditMod: function(){
  320. self = this
  321. var rubrics = this.options.parent_view.rubrics
  322. var select = this.make("select", {'className': "medium", 'name': "mediumSelect", 'id': "mediumSelect" }, "Bold! ")
  323. $(select).append(self.make("option",{'value':0}, 'Нет Рубрики' ) )
  324. rubrics.each(function(rubric){
  325. console.log(rubric.get('id'), self.model.get('rubric'))
  326. if (rubric.get('id') == self.model.get('rubric')){
  327. var option = self.make("option",{'value':rubric.get('id'), 'selected':'selected'}, rubric.get('name'))
  328. } else {
  329. var option = self.make("option",{'value':rubric.get('id')}, rubric.get('name'))
  330. }
  331. $(select).append(option)
  332. })
  333. this.el.find('.rubrika').html(select)
  334. this.rubric_edit_mod = true
  335. },
  336. rubricTurnOffEditMod: function(){
  337. this.rubric_edit_mod = false
  338. var select = this.el.find('.rubrika').find('select option:selected')
  339. var id = select.val()
  340. var text = select.text()
  341. this.model.set({'rubric':id, 'rubric_verbose':text})
  342. this.model.save()
  343. var t = this.make('span', {}, text)
  344. this.el.find('.rubrika').html(t)
  345. },
  346. image_path_changed: function(e){
  347. this.el.find('.favorite_folder_poster').find('img').attr('src', this.model.get('image_path'))
  348. },
  349. mark_count_changed: function(e){
  350. this.el.find(".mark_count").html(this.model.get('mark_count'))
  351. },
  352. shared_changed: function(e){
  353. if (this.model.get('shared')) {
  354. this.el.find('.stars_fave').fadeIn('fast') }
  355. else {
  356. this.el.find('.stars_fave').fadeOut('fast')
  357. }
  358. },
  359. idChanged: function(e){
  360. val = this.el.find('.fivestar').attr('action')
  361. this.el.find('.fivestar').attr('action', val.replace('//', '/'+this.model.get('id') +'/' ) )
  362. etv.common.Fivestar.initialize(".fivestar")
  363. },
  364. itemsChanged: function(e){
  365. items = this.model.get('items')
  366. this.el.find('.items_amout').html(items)
  367. if (items==0){
  368. this.el.find('.favorite_folder_poster').find('img').attr('src',this.empty_folder_image_url)
  369. }
  370. },
  371. durationChanged: function(e){
  372. this.el.find('.total_duration').html(this.model.get('duration'))
  373. },
  374. descChanged: function(e){
  375. this.el.find('.desc').find('span').html( this.model.get('desc_short'))
  376. },
  377. titleChanged: function(e){
  378. this.el.find('.tit').find('span').html(this.model.get('title_short'))
  379. },
  380. toggleEditMod: function(e){
  381. e.preventDefault()
  382. if (!this.edit_mod) { this.turn_edit_mod() }
  383. else { this.turn_of_edit_mod() }
  384. },
  385. toggleEditModDesc: function(e){
  386. e.preventDefault()
  387. if (!this.edit_mod_desc_flag) { this.edit_mod_desc({empty:false}) }
  388. else { this.turn_of_edit_mod_desc() }
  389. },
  390. toggleEditModTitle: function(e){
  391. e.preventDefault()
  392. if (!this.edit_mod_title_flag) { this.edit_mod_title({empty:false}) }
  393. else { this.turn_of_edit_mod_title() }
  394. },
  395. turn_edit_mod: function(){
  396. this.edit_mod_title()
  397. this.edit_mod_desc()
  398. this.rubricTurnEditMod()
  399. },
  400. edit_mod_title: function(options){
  401. if (!options) options = {empty:false}
  402. var val = this.model.get('title')
  403. val = options.empty ? '' : val
  404. this.el.find('.tit').find('span').html('<input class="input_edit" value="'+val+'" type="text" ></input>')
  405. this.edit_mod_title_flag = true;
  406. },
  407. edit_mod_desc: function(options){
  408. if (!options) options = {empty:false}
  409. val = this.model.get('description')
  410. val = options.empty ? '' : val
  411. this.el.find('.desc').find('span').html('<textarea class="area_edit" rows="4" cols="100">'+val+'</textarea>')
  412. this.edit_mod_desc_flag = true;
  413. },
  414. turn_of_edit_mod_title: function() {
  415. var title = this.el.find('.input_edit').val()
  416. var title_valid = this.model.set({title: title})
  417. if (title_valid) {
  418. this.edit_mod_title_flag = false
  419. this.model.trigger('change:title')
  420. this.model.save()
  421. }
  422. },
  423. turn_of_edit_mod_desc: function() {
  424. var desc = this.el.find('textarea').val()
  425. var desc_valid = this.model.set({description: desc})
  426. if (desc_valid) {
  427. this.edit_mod_desc_flag = false
  428. this.model.trigger('change:description')
  429. this.model.save()
  430. }
  431. },
  432. folderToggle: function(){
  433. if (!this.opend) { this.showLoader(); this.children.fetch({success: this.openFolder }) }
  434. else { this.children_container.slideUp(this.slideSpeed, this.closeFolder) }
  435. },
  436. openFolder : function(rs){
  437. this.hideLoader()
  438. if (rs.length !== 0) {
  439. this.options.parent_view.closeAllChildren()
  440. this.opend = true
  441. this.el.attr({'open':true})
  442. this.children_container.slideDown(this.slideSpeed)
  443. this.el.find('.open').attr({'class':'close'})
  444. this.el.find('.drop_shadow').css({'display':'inline'});
  445. this.el.find('.bottom_gray').hide();
  446. this.el.find('.drop_bottom').slideDown('fast');
  447. this.el.find('.scroll_fave').show();
  448. } else {
  449. this.el.find('.scroll_fave').hide();
  450. etv.utils.info_message('Папка "'+this.model.get('title')+'" пуста!')
  451. }
  452. },
  453. closeFolder: function(){
  454. this.opend = false
  455. this.children_container.html('')
  456. this.el.attr({'open':false})
  457. this.el.find('.close').attr({'class':'open'})
  458. this.el.find('.drop_shadow').css({'display':'none'});
  459. this.el.find('.bottom_gray').show();
  460. this.el.find('.drop_bottom').slideUp('fast');
  461. this.el.find('.scroll_fave').hide();
  462. },
  463. removeFolder: function(e){
  464. e.preventDefault();
  465. this.model.destroy();
  466. this.el.slideUp('slow', function(){this.remove})
  467. },
  468. render: function(){
  469. $(this.el).html(this.template(this.model.toJSON()))
  470. this.el.find('input').change(this.confirmSharedChanged)
  471. return this
  472. },
  473. confirmSharedChanged: function(){
  474. var val = $(this.el).find('input[name=shared]:checked').attr('value')
  475. if(val==1) {
  476. etv.utils.dialog_message(this.confirm_shared_message(), this.sharedChanged)
  477. } else {
  478. this.model.set({'shared':val})
  479. this.model.save()
  480. }
  481. },
  482. sharedChanged: function(confirm){
  483. var val = $(this.el).find('input[name=shared]:checked').attr('value')
  484. if (confirm) {
  485. var val = $(this.el).find('input[name=shared]:checked').attr('value')
  486. this.model.set({'shared':val})
  487. this.model.save()
  488. } else {
  489. $(this.el).find('input[name=shared]')[1].checked = 'checked';
  490. }
  491. },
  492. handleValidationError: function(model, error){
  493. if (typeof(error)=='string') {
  494. etv.utils.error_message(error)
  495. }
  496. }
  497. });
  498. // Bookmarks Main Viev
  499. etv.vid.bmark.BookmarksView = etv.vid.bmark.BaseView.extend({
  500. collection_class : etv.vid.bmark.Folders,
  501. childrens_view: etv.vid.bmark.FolderView,
  502. events: {
  503. "click .add_folder": "emptyForm",
  504. },
  505. initialize: function(attributes,options){
  506. this.rubrics = new etv.vid.bmark.FolderRubric
  507. this.rubrics.fetch()
  508. this.model = new etv.vid.bmark.AppModel
  509. etv.vid.bmark.BaseView.prototype.initialize.call(this, attributes, options);
  510. this.children.fetch()
  511. },
  512. closeAllChildren: function(){
  513. _.map(this.children_views, (function(view){
  514. if (view.opend) {
  515. view.children_container.slideUp(view.slideSpeed, view.closeFolder)
  516. };
  517. })
  518. )
  519. },
  520. emptyForm: function(e){
  521. e.preventDefault()
  522. var model = new etv.vid.bmark.Folder;
  523. this.children.add(model,{at:0});
  524. this.children_views[this.children_views.length-1].turn_edit_mod();
  525. }
  526. });