<commit_before>/**
 *
 * Note List View
 *
 * noteListView.js
 * @author Kerri Shotts
 * @version 1.0.0
 *
 * Copyright (c) 2013 PacktPub Publishing
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
/*jshint
 asi:true,
 bitwise:true,
 browser:true,
 curly:true,
 eqeqeq:false,
 forin:true,
 noarg:true,
 noempty:true,
 plusplus:false,
 smarttabs:true,
 sub:true,
 trailing:false,
 undef:true,
 white:false,
 onevar:false
 */
/*global define*/

define ( ["yasmf",
          "app/models/noteStorageSingleton",
          "text!html/noteListView.html!strip",
          "text!html/noteListItem.html!strip",
          "app/factories/noteFactory",
          "app/factories/noteViewFactory",
          "app/views/staticView",
          "hammer"],
         function ( _y, noteStorageSingleton, noteListViewHTML,
                    noteListItemHTML,
                    noteFactory, noteViewFactory, StaticView, Hammer )
         {
           var _className = "NoteListView";
           var NoteListView = function ()
           {
             // we descend from a simple ViewContainer
             var self = new _y.UI.ViewContainer ();
             // always subclass
             self.subclass ( _className );

             // our pointers into the DOM
             self._navigationBar = null;
             self._scrollContainer = null;
             self._listOfNotes = null;
             self._newTextNoteButton = null;
             self._newAudioNoteButton = null;
             self._newImageNoteButton = null;
             self._newVideoNoteButton = null;

             self._displayEditView = function (theView)
             {
               if (typeof self.navigationController.splitViewController !== "undefined")
               {
                 var rightView = self.navigationController.splitViewController.rightView;
                 if (rightView.topView.class !== "StaticView")
                 {
                   // we have an edit in-progress. Save it first.
                   rightView.topView.saveNote();
                 }
                 // change the root view of the right-side of the split view
                 self.navigationController.splitViewController.rightView.rootView = theView;
               }
               else
               {
                 self.navigationController.pushView(theView);
               }
             };

             self._createAndEditNote = function (noteType)
             {
               // ask storage for a new note
               noteStorageSingleton.createNote(noteType)
                 .then(function (aNewNote)
                       {
                         // create a new editor view
                         var aNoteEditView = noteViewFactory.createNoteEditView(noteType);
                         // and tell it about the new note
                         aNoteEditView.initWithOptions({note: aNewNote});
                         self._displayEditView(aNoteEditView);
                       })
                 .catch(function (anError) { console.log(anError) })
                 .done();

             };
             /**
              * Creates a new note; called when "New" is tapped
              */
             self.createNewTextNote = function ()
             {
               self._createAndEditNote(noteFactory.TEXTNOTE);
             };

             self.createNewAudioNote = function ()
             {
               self._createAndEditNote(noteFactory.AUDIONOTE);
             };

             self.createNewImageNote = function ()
             {
               self._createAndEditNote(noteFactory.IMAGENOTE);
             };

             self.createNewVideoNote = function ()
             {
               self._createAndEditNote(noteFactory.VIDEONOTE);
             };

             /**
              * Edit an existing note. Called when a note item is tapped in the list.
              */
             self.editExistingNote = function ()
             {
               // get the UID
               var theUID = this.getAttribute("data-uid");
               // create a new editor view
               var aNote = noteStorageSingleton.getNote(theUID);
               var aNoteEditView = noteViewFactory.createNoteEditView(aNote.class);
               // and tell it about the note
               aNoteEditView.initWithOptions({note: aNote });
               self._displayEditView(aNoteEditView);
             };

             self.deleteExistingNote = function ()
             {
               // get the UID
               var theUID = this.getAttribute("data-uid");

               noteStorageSingleton.removeNote(theUID);

               // display a static view if we have a splitview, but only if we're deleting
               // the currently visible note
               if (typeof self.navigationController.splitViewController !== "undefined")
               {
                 var topView = self.navigationController.splitViewController.rightView.topView;
                 if (topView.class !== "StaticView")
                 {
                   if (topView.getNoteUID() == theUID)
                   {
                     var staticView = new StaticView();
                     staticView.initWithOptions();
                     self.navigationController.splitViewController.rightView.rootView = staticView;
                   }
                 }
               }
             };

             self.popupActionsForNote = function (e)
             {
               e.gesture.preventDefault();
               var theUID = this.getAttribute("data-uid");

               var anAlert = new _y.UI.Alert();
               anAlert.initWithOptions(
                 { title:   _y.T("NOTE_ACTIONS"),
                   text:    _y.T("SELECT_AN_ACTION_OR_CANCEL"),
                   promise: true,
                   buttons: [ _y.UI.Alert.button(_y.T("DELETE"), { type: "destructive" }),
                              _y.UI.Alert.button(_y.T("CANCEL"), { type: "bold", tag: -1 })
                   ] });
               anAlert.show()
                 .then(function (idx)
                       {
                         if (idx == 0)
                         {
                           noteStorageSingleton.removeNote(theUID);
                         }
                       })
                 .catch(function (e) { console.log("Promise rejected: " + e); })
                 .done();
             };

             self.exposeActionForNote = function (e)
             {
               e.gesture.preventDefault();
               _y.UI.styleElement(this, "transition", "%PREFIX%transform 0.3s ease-in-out");
               // how far do we have to go?
               var amountToTranslate = getComputedStyle(self._listOfNotes.querySelector(".ui-list-action")).getPropertyValue("width");
               _y.UI.styleElement(this, "transform", "translateX(-" + amountToTranslate + ")");
             };

             self.hideActionForNote = function (e)
             {
               e.gesture.preventDefault();
               _y.UI.styleElement(this, "transition", "%PREFIX%transform 0.3s ease-in-out");
               _y.UI.styleElement(this, "transform", "translateX(0px)");
             };
             /**
              * Quit the app, in response to a back button event.
              */
             self.quitApp = function ()
             {
               // only called on platforms that support going back on the first page
               // on iOS we don't have a back button to call it.
               //
               // note: not guaranteed to always work
               navigator.app.exitApp();
             };

             /**
              * Render the template, passing the app title and translated text
              */
             self.overrideSuper ( self.class, "render", self.render );
             self.render = function ()
             {
               // no need to call super; it's abstract
               return _y.template(noteListViewHTML,
                                  {
                                    "APP_TITLE": _y.T("APP_TITLE"),
                                    "NEW_NOTE":  _y.T("NEW_NOTE")
                                  });
             };

             /**
              * RenderToElement renders the HTML, finds all the elements we want to
              * have references to and attaches handlers if necessary,
              * and attaches a listener to the backButton handler.
              */
             self.overrideSuper ( self.class, "renderToElement", self.renderToElement );
             self.renderToElement = function ()
             {
               // call super, which will also get our HTML into the element
               self.super(_className, "renderToElement");

               // and now find and link up any elements we want to keep track of
               self._navigationBar = self.element.querySelector(".ui-navigation-bar");
               self._scrollContainer = self.element.querySelector(".ui-scroll-container");
               self._listOfNotes = self.element.querySelector(".ui-list");

               // all our "new" buttons:
               var newButtons = self.element.querySelectorAll(".ui-tool-bar .ui-bar-button");
               self._newTextNoteButton = newButtons[0];
               self._newAudioNoteButton = newButtons[1];
               self._newImageNoteButton = newButtons[2];
               self._newVideoNoteButton = newButtons[3];

               // the new Button should have an event listener
               //_y.UI.event.addListener ( self._newButton, "click", self.createNewNote );
               Hammer(self._newTextNoteButton).on("tap", self.createNewTextNote);
               Hammer(self._newAudioNoteButton).on("tap", self.createNewAudioNote);
               Hammer(self._newImageNoteButton).on("tap", self.createNewImageNote);
               Hammer(self._newVideoNoteButton).on("tap", self.createNewVideoNote);

               // and make sure we know about the physical back button
               _y.UI.backButton.addListenerForNotification("backButtonPressed", self.quitApp);
             };

             /**
              * Render the note list; called whenever the storage collection changes
              */
             self.renderList = function ()
             {
               if (_y.device.isTablet() &&
                   parseInt(window.getComputedStyle(self.element).getPropertyValue("width"), 10) >= 320)
               {
                 self.element.classList.add("wide");
               }
               var notes = noteStorageSingleton.collection;

               var fragment = document.createDocumentFragment();

               // loop over each note
               for (var note in notes)
               {
                 // and avoid prototype entries
                 if (notes.hasOwnProperty(note))
                 {
                   // null notes have been deleted -- don't show them
                   if (notes[note] !== null)
                   {
                     // each entry is a li.ui-list-item with data-uid attribute and note_item_% as the id.
                     var e = document.createElement("li");
                     e.className = "ui-list-item";
                     e.setAttribute("data-uid", notes[note].uid);
                     e.id = "note_item_" + notes[note].uid;

                     // render the note item template
                     e.innerHTML = _y.template(noteListItemHTML,
                                               {
                                                 "UID":            notes[note].uid,
                                                 "TRASH":          _y.T("TRASH"),
                                                 "NAME":           notes[note].name,
                                                 "REPRESENTATION": notes[note].representation,
                                                 "MODIFIED":       _y.D(notes[note].modifiedDate, "D"),
                                                 "INFO": "" + _y.N(notes[note].formattedUnitValue)
                                               });
                     // attach any event handlers
                     var contentsElement = e.querySelector(".ui-list-item-contents"),
                       actionElement = e.querySelector(".ui-list-action");

                     Hammer(contentsElement).on("tap", self.editExistingNote);

                     if (!self.element.classList.contains("wide"))
                     {
                       // the following is applicable only when we're rendering a list view
                       // (not a thumbnail view)
                       Hammer(contentsElement, {swipe_velocity: 0.1}).on("swipeleft", self.exposeActionForNote);
                       Hammer(contentsElement, {swipe_velocity: 0.1 }).on("swiperight", self.hideActionForNote);
                       Hammer(actionElement).on("tap", self.deleteExistingNote);
                     }
                     else
                     {
                       // but we'll allow a long-press on the item instead
                       Hammer(contentsElement).on("hold", self.popupActionsForNote);
                     }

                     // append the element to our list
                     fragment.appendChild(e);
                   }
                 }
               }
               self._listOfNotes.innerHTML = "";
               self._listOfNotes.appendChild(fragment);
             };

             self.onOrientationChanged = function ()
             {
               // fix a iOS bug where rotation may prevent the list from scrolling after rotation
               if (_y.device.platform() == "ios")
               {
                 // this forces the scroll container to be recalc'd. It also flickers a bit.
                 // no way to avoid it, unfortunately.
                 self._scrollContainer.style.display = "none";
                 setTimeout(function () { self._scrollContainer.style.display = ""; }, 0);
               }
             };

             /**
              * Initialize the view and add listeners for the storage
              * collection so that when it changes, we can update appropriately
              */
             self.overrideSuper ( self.class, "init", self.init );
             self.init = function (theParentElement)
             {
               // call super
               self.super(_className, "init", [undefined, "div", "noteListView ui-container", theParentElement]);

               // register for changes in the note collection
               noteStorageSingleton.addListenerForNotification("collectionChanged", self.renderList);
               noteStorageSingleton.addListenerForNotification("collectionLoaded", self.renderList);

               // and ask noteStorage to load itself
               noteStorageSingleton.loadCollection();

               // we need to register for orientation changes
               _y.UI.orientationHandler.addListenerForNotification("orientationChanged", self.onOrientationChanged);
             };

             self.overrideSuper ( self.class, "initWithOptions", self.init );
             self.initWithOptions = function (options)
             {
               var theParentElement;
               if (typeof options !== "undefined")
               {
                 if (typeof options.parent !== "undefined")
                 {
                   theParentElement = options.parent;
                 }
               }

               self.init(theParentElement);
             };

             /**
              * Be a good citizen. Clean up after ourselves when asked.
              */
             self.overrideSuper ( self.class, "destroy", self.destroy );
             self.destroy = function ()
             {
               // stop listening for orientation changes
               _y.UI.orientationHandler.removeListenerForNotification("orientationChanged", self.onOrientationChanged);

               // release our objects
               self._navigationBar = null;
               self._newTextNoteButton = null;
               self._newAudioNoteButton = null;
               self._newVideoNoteButton = null;
               self._newImageNoteButton = null;
               self._scrollContainer = null;
               self._listOfNotes = null;

               self.super(_className, "destroy");
             };

             return self;
           };

           /**
            * Add the necessary translations
            */
           _y.addTranslations (
             {
               "APP_TITLE":
               {
                 "EN": "Filer"
               },
               "NEW_NOTE":
               {
                 "EN": "New",
                 "ES": "Nueva"
               },
               "BACK":
               {
                 "EN": "Back",
                 "ES": "Volver"
               },
               "TRASH":
               {
                 "EN": "Trash",
                 "ES": "Basura"
               },
               "CANCEL":
               {
                 "EN": "Cancel",
                 "ES": "Cancelar"
               },
               "DELETE":
               {
                 "EN": "Delete",
                 "ES": "Eliminar"
               },
               "NOTE_ACTIONS":
               {
                 "EN": "Note Actions",
                 "ES": "Acciónes para la nota"
               },
               "SELECT_AN_ACTION_OR_CANCEL":
               {
                 "EN": "Select an action for this note, or cancel.",
                 "ES": "Seleccione un acción para esta nota, o cancelar."
               }
             });

           return NoteListView;

         });<commit_msg>Switch from swipes to drags; better response<commit_after>/**
 *
 * Note List View
 *
 * noteListView.js
 * @author Kerri Shotts
 * @version 1.0.0
 *
 * Copyright (c) 2013 PacktPub Publishing
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
/*jshint
 asi:true,
 bitwise:true,
 browser:true,
 curly:true,
 eqeqeq:false,
 forin:true,
 noarg:true,
 noempty:true,
 plusplus:false,
 smarttabs:true,
 sub:true,
 trailing:false,
 undef:true,
 white:false,
 onevar:false
 */
/*global define*/

define ( ["yasmf",
          "app/models/noteStorageSingleton",
          "text!html/noteListView.html!strip",
          "text!html/noteListItem.html!strip",
          "app/factories/noteFactory",
          "app/factories/noteViewFactory",
          "app/views/staticView",
          "hammer"],
         function ( _y, noteStorageSingleton, noteListViewHTML,
                    noteListItemHTML,
                    noteFactory, noteViewFactory, StaticView, Hammer )
         {
           var _className = "NoteListView";
           var NoteListView = function ()
           {
             // we descend from a simple ViewContainer
             var self = new _y.UI.ViewContainer ();
             // always subclass
             self.subclass ( _className );

             // our pointers into the DOM
             self._navigationBar = null;
             self._scrollContainer = null;
             self._listOfNotes = null;
             self._newTextNoteButton = null;
             self._newAudioNoteButton = null;
             self._newImageNoteButton = null;
             self._newVideoNoteButton = null;

             self._displayEditView = function (theView)
             {
               if (typeof self.navigationController.splitViewController !== "undefined")
               {
                 var rightView = self.navigationController.splitViewController.rightView;
                 if (rightView.topView.class !== "StaticView")
                 {
                   // we have an edit in-progress. Save it first.
                   rightView.topView.saveNote();
                 }
                 // change the root view of the right-side of the split view
                 self.navigationController.splitViewController.rightView.rootView = theView;
               }
               else
               {
                 self.navigationController.pushView(theView);
               }
             };

             self._createAndEditNote = function (noteType)
             {
               // ask storage for a new note
               noteStorageSingleton.createNote(noteType)
                 .then(function (aNewNote)
                       {
                         // create a new editor view
                         var aNoteEditView = noteViewFactory.createNoteEditView(noteType);
                         // and tell it about the new note
                         aNoteEditView.initWithOptions({note: aNewNote});
                         self._displayEditView(aNoteEditView);
                       })
                 .catch(function (anError) { console.log(anError) })
                 .done();

             };
             /**
              * Creates a new note; called when "New" is tapped
              */
             self.createNewTextNote = function ()
             {
               self._createAndEditNote(noteFactory.TEXTNOTE);
             };

             self.createNewAudioNote = function ()
             {
               self._createAndEditNote(noteFactory.AUDIONOTE);
             };

             self.createNewImageNote = function ()
             {
               self._createAndEditNote(noteFactory.IMAGENOTE);
             };

             self.createNewVideoNote = function ()
             {
               self._createAndEditNote(noteFactory.VIDEONOTE);
             };

             /**
              * Edit an existing note. Called when a note item is tapped in the list.
              */
             self.editExistingNote = function ()
             {
               // get the UID
               var theUID = this.getAttribute("data-uid");
               // create a new editor view
               var aNote = noteStorageSingleton.getNote(theUID);
               var aNoteEditView = noteViewFactory.createNoteEditView(aNote.class);
               // and tell it about the note
               aNoteEditView.initWithOptions({note: aNote });
               self._displayEditView(aNoteEditView);
             };

             self.deleteExistingNote = function ()
             {
               // get the UID
               var theUID = this.getAttribute("data-uid");

               noteStorageSingleton.removeNote(theUID);

               // display a static view if we have a splitview, but only if we're deleting
               // the currently visible note
               if (typeof self.navigationController.splitViewController !== "undefined")
               {
                 var topView = self.navigationController.splitViewController.rightView.topView;
                 if (topView.class !== "StaticView")
                 {
                   if (topView.getNoteUID() == theUID)
                   {
                     var staticView = new StaticView();
                     staticView.initWithOptions();
                     self.navigationController.splitViewController.rightView.rootView = staticView;
                   }
                 }
               }
             };

             self.popupActionsForNote = function (e)
             {
               e.gesture.preventDefault();
               var theUID = this.getAttribute("data-uid");

               var anAlert = new _y.UI.Alert();
               anAlert.initWithOptions(
                 { title:   _y.T("NOTE_ACTIONS"),
                   text:    _y.T("SELECT_AN_ACTION_OR_CANCEL"),
                   promise: true,
                   buttons: [ _y.UI.Alert.button(_y.T("DELETE"), { type: "destructive" }),
                              _y.UI.Alert.button(_y.T("CANCEL"), { type: "bold", tag: -1 })
                   ] });
               anAlert.show()
                 .then(function (idx)
                       {
                         if (idx == 0)
                         {
                           noteStorageSingleton.removeNote(theUID);
                         }
                       })
                 .catch(function (e) { console.log("Promise rejected: " + e); })
                 .done();
             };

             self.exposeActionForNote = function (e)
             {
               e.gesture.preventDefault();
               _y.UI.styleElement(this, "transition", "%PREFIX%transform 0.3s ease-in-out");
               // how far do we have to go?
               var amountToTranslate = getComputedStyle(self._listOfNotes.querySelector(".ui-list-action")).getPropertyValue("width");
               _y.UI.styleElement(this, "transform", "translateX(-" + amountToTranslate + ")");
             };

             self.hideActionForNote = function (e)
             {
               e.gesture.preventDefault();
               _y.UI.styleElement(this, "transition", "%PREFIX%transform 0.3s ease-in-out");
               _y.UI.styleElement(this, "transform", "translateX(0px)");
             };
             /**
              * Quit the app, in response to a back button event.
              */
             self.quitApp = function ()
             {
               // only called on platforms that support going back on the first page
               // on iOS we don't have a back button to call it.
               //
               // note: not guaranteed to always work
               navigator.app.exitApp();
             };

             /**
              * Render the template, passing the app title and translated text
              */
             self.overrideSuper ( self.class, "render", self.render );
             self.render = function ()
             {
               // no need to call super; it's abstract
               return _y.template(noteListViewHTML,
                                  {
                                    "APP_TITLE": _y.T("APP_TITLE"),
                                    "NEW_NOTE":  _y.T("NEW_NOTE")
                                  });
             };

             /**
              * RenderToElement renders the HTML, finds all the elements we want to
              * have references to and attaches handlers if necessary,
              * and attaches a listener to the backButton handler.
              */
             self.overrideSuper ( self.class, "renderToElement", self.renderToElement );
             self.renderToElement = function ()
             {
               // call super, which will also get our HTML into the element
               self.super(_className, "renderToElement");

               // and now find and link up any elements we want to keep track of
               self._navigationBar = self.element.querySelector(".ui-navigation-bar");
               self._scrollContainer = self.element.querySelector(".ui-scroll-container");
               self._listOfNotes = self.element.querySelector(".ui-list");

               // all our "new" buttons:
               var newButtons = self.element.querySelectorAll(".ui-tool-bar .ui-bar-button");
               self._newTextNoteButton = newButtons[0];
               self._newAudioNoteButton = newButtons[1];
               self._newImageNoteButton = newButtons[2];
               self._newVideoNoteButton = newButtons[3];

               // the new Button should have an event listener
               //_y.UI.event.addListener ( self._newButton, "click", self.createNewNote );
               Hammer(self._newTextNoteButton).on("tap", self.createNewTextNote);
               Hammer(self._newAudioNoteButton).on("tap", self.createNewAudioNote);
               Hammer(self._newImageNoteButton).on("tap", self.createNewImageNote);
               Hammer(self._newVideoNoteButton).on("tap", self.createNewVideoNote);

               // and make sure we know about the physical back button
               _y.UI.backButton.addListenerForNotification("backButtonPressed", self.quitApp);
             };

             /**
              * Render the note list; called whenever the storage collection changes
              */
             self.renderList = function ()
             {
               if (_y.device.isTablet() &&
                   parseInt(window.getComputedStyle(self.element).getPropertyValue("width"), 10) >= 320)
               {
                 self.element.classList.add("wide");
               }
               var notes = noteStorageSingleton.collection;

               var fragment = document.createDocumentFragment();

               // loop over each note
               for (var note in notes)
               {
                 // and avoid prototype entries
                 if (notes.hasOwnProperty(note))
                 {
                   // null notes have been deleted -- don't show them
                   if (notes[note] !== null)
                   {
                     // each entry is a li.ui-list-item with data-uid attribute and note_item_% as the id.
                     var e = document.createElement("li");
                     e.className = "ui-list-item";
                     e.setAttribute("data-uid", notes[note].uid);
                     e.id = "note_item_" + notes[note].uid;

                     // render the note item template
                     e.innerHTML = _y.template(noteListItemHTML,
                                               {
                                                 "UID":            notes[note].uid,
                                                 "TRASH":          _y.T("TRASH"),
                                                 "NAME":           notes[note].name,
                                                 "REPRESENTATION": notes[note].representation,
                                                 "MODIFIED":       _y.D(notes[note].modifiedDate, "D"),
                                                 "INFO": "" + _y.N(notes[note].formattedUnitValue)
                                               });
                     // attach any event handlers
                     var contentsElement = e.querySelector(".ui-list-item-contents"),
                       actionElement = e.querySelector(".ui-list-action");

                     Hammer(contentsElement).on("tap", self.editExistingNote);

                     if (!self.element.classList.contains("wide"))
                     {
                       // the following is applicable only when we're rendering a list view
                       // (not a thumbnail view)
                       Hammer(contentsElement, {swipe_velocity: 0.1, drag_block_horizontal:true,drag_block_vertical:true, prevent_default:true }).on("dragleft", self.exposeActionForNote);
                       Hammer(contentsElement, {swipe_velocity: 0.1, drag_block_horizontal:true,drag_block_vertical:true, prevent_default:true }).on("dragright", self.hideActionForNote);
                       Hammer(actionElement).on("tap", self.deleteExistingNote);
                     }
                     else
                     {
                       // but we'll allow a long-press on the item instead
                       Hammer(contentsElement).on("hold", self.popupActionsForNote);
                     }

                     // append the element to our list
                     fragment.appendChild(e);
                   }
                 }
               }
               self._listOfNotes.innerHTML = "";
               self._listOfNotes.appendChild(fragment);
             };

             self.onOrientationChanged = function ()
             {
               // fix a iOS bug where rotation may prevent the list from scrolling after rotation
               if (_y.device.platform() == "ios")
               {
                 // this forces the scroll container to be recalc'd. It also flickers a bit.
                 // no way to avoid it, unfortunately.
                 self._scrollContainer.style.display = "none";
                 setTimeout(function () { self._scrollContainer.style.display = ""; }, 0);
               }
             };

             /**
              * Initialize the view and add listeners for the storage
              * collection so that when it changes, we can update appropriately
              */
             self.overrideSuper ( self.class, "init", self.init );
             self.init = function (theParentElement)
             {
               // call super
               self.super(_className, "init", [undefined, "div", "noteListView ui-container", theParentElement]);

               // register for changes in the note collection
               noteStorageSingleton.addListenerForNotification("collectionChanged", self.renderList);
               noteStorageSingleton.addListenerForNotification("collectionLoaded", self.renderList);

               // and ask noteStorage to load itself
               noteStorageSingleton.loadCollection();

               // we need to register for orientation changes
               _y.UI.orientationHandler.addListenerForNotification("orientationChanged", self.onOrientationChanged);
             };

             self.overrideSuper ( self.class, "initWithOptions", self.init );
             self.initWithOptions = function (options)
             {
               var theParentElement;
               if (typeof options !== "undefined")
               {
                 if (typeof options.parent !== "undefined")
                 {
                   theParentElement = options.parent;
                 }
               }

               self.init(theParentElement);
             };

             /**
              * Be a good citizen. Clean up after ourselves when asked.
              */
             self.overrideSuper ( self.class, "destroy", self.destroy );
             self.destroy = function ()
             {
               // stop listening for orientation changes
               _y.UI.orientationHandler.removeListenerForNotification("orientationChanged", self.onOrientationChanged);

               // release our objects
               self._navigationBar = null;
               self._newTextNoteButton = null;
               self._newAudioNoteButton = null;
               self._newVideoNoteButton = null;
               self._newImageNoteButton = null;
               self._scrollContainer = null;
               self._listOfNotes = null;

               self.super(_className, "destroy");
             };

             return self;
           };

           /**
            * Add the necessary translations
            */
           _y.addTranslations (
             {
               "APP_TITLE":
               {
                 "EN": "Filer"
               },
               "NEW_NOTE":
               {
                 "EN": "New",
                 "ES": "Nueva"
               },
               "BACK":
               {
                 "EN": "Back",
                 "ES": "Volver"
               },
               "TRASH":
               {
                 "EN": "Trash",
                 "ES": "Basura"
               },
               "CANCEL":
               {
                 "EN": "Cancel",
                 "ES": "Cancelar"
               },
               "DELETE":
               {
                 "EN": "Delete",
                 "ES": "Eliminar"
               },
               "NOTE_ACTIONS":
               {
                 "EN": "Note Actions",
                 "ES": "Acciónes para la nota"
               },
               "SELECT_AN_ACTION_OR_CANCEL":
               {
                 "EN": "Select an action for this note, or cancel.",
                 "ES": "Seleccione un acción para esta nota, o cancelar."
               }
             });

           return NoteListView;

         });<|endoftext|>


<commit_before><commit_msg>Provided support for clipping-based shape transitions (barnWipe, fourBoxWipe, ellipseWipe, pinWheelWipe). Basic support for reverse method by subtraction.<commit_after><|endoftext|>


<commit_before>import Ember from 'ember';
import layout from '../templates/components/scroll-content-element';
import DomMixin from 'ember-lifeline/mixins/dom';
import { styleify } from '../util/css';
import Number from '../util/number';

const {
  computed,
  run: {
    schedule
  }
} = Ember;

/**
 *
 * Handles scroll events within the body of the scroll content,
 * properly sets scrollTop / scrollLeft property depending on the configuration and the given scrollTo.
 *
 * @class ScrollContentElement
 * @extends Ember.Component
 */
export default Ember.Component.extend(DomMixin, {
  /**
   * Adds the `tse-scroll-content` class to this element which is in charge of removing the default scrollbar(s) from
   * this element (the container for the content being scrolled). Also the `tse-scroll-content` class enables
   * overflow to trigger scroll events although this element doesn't have a native scrollbar.
   *
   * @property  classNameBindings
   * @public
   * @type Array
   */
  classNameBindings: [':tse-scroll-content'],
  attributeBindings: ['style'],
  layout,
  /**
   * Callback function when scroll event occurs.
   * Arguments are: jQueryEvent, scrollOffset, and horizontal'|'vertical'
   * @property onScroll
   * @public
   * @type Function
   */
  onScroll(){},

  /**
   * Height of this content. Note content must have a height that is larger than this in order to cause overflow-y,
   * and enabling scrolling.
   *
   * @property height
   * @public
   * @type Number
   */
  height: null,

  /**
   * Width of this content. Note contnet must have a width that is larger than this in order to cause overflow-x
   * therefore enabling scrolling.
   *
   * @property width
   * @public
   * @type Number
   */
  width: null,

  /**
   * Integer representing desired scrollLeft to be set for this element.
   *
   * @property scrollToX
   * @public
   * @type Number
   * @default 0
   */
  scrollToX: 0,

  /**
   * Integer representing desired scrollTop to be set for this element.
   *
   * @property scrollToX
   * @public
   * @type Number
   * @default 0
   */
  scrollToY: 0,

  /**
   * Intermediate object to collect style attributes. Height and width are set dynamically such that space is allocated
   * for the given scrollbars that will be rendered.
   *
   * @property stylesJSON
   * @private
   */
  stylesJSON: computed('height', 'width', function() {
    const { height, width } = this.getProperties('height', 'width');
    return { width: width + 'px', height: height + 'px' };
  }),

  /**
   * String bound to the style attribute.
   *
   * @property style
   * @private
   * @type String
   */
  style: computed('stylesJSON.{height,width}', function() {
    return styleify(this.get('stylesJSON'));
  }),

  /**
   * Previous scrollToX value. Useful for calculating changes in scrollToX.
   *
   * @property previousScrollToX
   * @private
   * @type Number
   */
  previousScrollToX: 0,

  /**
   * Previous scrollToY value. Useful for calculating changes in scrollToY.
   *
   * @property previousScrollToY
   * @private
   * @type Number
   */
  previousScrollToY: 0,

  /**
   * Callback from scroll event on the content of this element.
   * Determines direction of scroll and calls the `onScroll` action with:
   *  - the jQueryEvent
   *  - the scrollOffset -- indicates positioning from top/left anchor point
   *  - 'horizontal' | 'vertical' -- indicates direction of scroll
   *
   * @method scrolled
   * @param e jQueryEvent
   */
  scrolled(e) {
    const newScrollLeft = e.target.scrollLeft;
    const newScrollTop = e.target.scrollTop;

    if (newScrollLeft !== this.get('previousScrollToX')) {
      this.get('onScroll')(e, newScrollLeft, 'horizontal');
      this.set(`previousScrollToX`, newScrollLeft);
    } else if (newScrollTop !== this.get('previousScrollToY')) {
      this.get('onScroll')(e, newScrollTop, 'vertical');
      this.set(`previousScrollToY`, newScrollTop);
    }
  },

  /**
   * Sets the scroll property (scrollTop, or scrollLeft) for the given the direction and offset.
   *
   * @method scrollToPosition
   * @private
   * @param offset  Number -- offset amount in pixels
   * @param direction String -- 'X' | 'Y' -- indicates what direction is being scrolled
   */
  scrollToPosition(offset, direction) {
    offset = Number.parseInt(offset, 10);

    if (Number.isNaN(offset)) {
      return;
    }
    const scrollOffsetAttr = direction === 'X' ? 'scrollLeft' : 'scrollTop';
    this.$()[scrollOffsetAttr](offset);
  },

  configureInitialScrollPosition() {
    this.scrollToPosition(this.get('scrollToX'), 'X');
    this.scrollToPosition(this.get('scrollToY'), 'Y');
  },

  didInsertElement() {
    this._super(...arguments);
    this.addEventListener(this.$(), 'scroll', (e) => {
      this.scrolled(e);
    });
    this.configureInitialScrollPosition();
  },

  didReceiveAttrs() {
    // Sync property changes to `scrollToX` and `scrollToY` with the `scrollTop` and `scrollLeft` attributes
    // of the rendered DOM element.
    ['X', 'Y'].forEach((direction) => {
      const oldOffset = this.get(`previousScrollTo${direction}`);
      const newOffset = this.get(`scrollTo${direction}`);

      if (oldOffset !== newOffset) {
        schedule('afterRender', this, this.scrollToPosition, newOffset, direction);
      }
    });
  }

});

<commit_msg>Pass only one element to addEventListener<commit_after>import Ember from 'ember';
import layout from '../templates/components/scroll-content-element';
import DomMixin from 'ember-lifeline/mixins/dom';
import { styleify } from '../util/css';
import Number from '../util/number';

const {
  computed,
  run: {
    schedule
  }
} = Ember;

/**
 *
 * Handles scroll events within the body of the scroll content,
 * properly sets scrollTop / scrollLeft property depending on the configuration and the given scrollTo.
 *
 * @class ScrollContentElement
 * @extends Ember.Component
 */
export default Ember.Component.extend(DomMixin, {
  /**
   * Adds the `tse-scroll-content` class to this element which is in charge of removing the default scrollbar(s) from
   * this element (the container for the content being scrolled). Also the `tse-scroll-content` class enables
   * overflow to trigger scroll events although this element doesn't have a native scrollbar.
   *
   * @property  classNameBindings
   * @public
   * @type Array
   */
  classNameBindings: [':tse-scroll-content'],
  attributeBindings: ['style'],
  layout,
  /**
   * Callback function when scroll event occurs.
   * Arguments are: jQueryEvent, scrollOffset, and horizontal'|'vertical'
   * @property onScroll
   * @public
   * @type Function
   */
  onScroll(){},

  /**
   * Height of this content. Note content must have a height that is larger than this in order to cause overflow-y,
   * and enabling scrolling.
   *
   * @property height
   * @public
   * @type Number
   */
  height: null,

  /**
   * Width of this content. Note contnet must have a width that is larger than this in order to cause overflow-x
   * therefore enabling scrolling.
   *
   * @property width
   * @public
   * @type Number
   */
  width: null,

  /**
   * Integer representing desired scrollLeft to be set for this element.
   *
   * @property scrollToX
   * @public
   * @type Number
   * @default 0
   */
  scrollToX: 0,

  /**
   * Integer representing desired scrollTop to be set for this element.
   *
   * @property scrollToX
   * @public
   * @type Number
   * @default 0
   */
  scrollToY: 0,

  /**
   * Intermediate object to collect style attributes. Height and width are set dynamically such that space is allocated
   * for the given scrollbars that will be rendered.
   *
   * @property stylesJSON
   * @private
   */
  stylesJSON: computed('height', 'width', function() {
    const { height, width } = this.getProperties('height', 'width');
    return { width: width + 'px', height: height + 'px' };
  }),

  /**
   * String bound to the style attribute.
   *
   * @property style
   * @private
   * @type String
   */
  style: computed('stylesJSON.{height,width}', function() {
    return styleify(this.get('stylesJSON'));
  }),

  /**
   * Previous scrollToX value. Useful for calculating changes in scrollToX.
   *
   * @property previousScrollToX
   * @private
   * @type Number
   */
  previousScrollToX: 0,

  /**
   * Previous scrollToY value. Useful for calculating changes in scrollToY.
   *
   * @property previousScrollToY
   * @private
   * @type Number
   */
  previousScrollToY: 0,

  /**
   * Callback from scroll event on the content of this element.
   * Determines direction of scroll and calls the `onScroll` action with:
   *  - the jQueryEvent
   *  - the scrollOffset -- indicates positioning from top/left anchor point
   *  - 'horizontal' | 'vertical' -- indicates direction of scroll
   *
   * @method scrolled
   * @param e jQueryEvent
   */
  scrolled(e) {
    const newScrollLeft = e.target.scrollLeft;
    const newScrollTop = e.target.scrollTop;

    if (newScrollLeft !== this.get('previousScrollToX')) {
      this.get('onScroll')(e, newScrollLeft, 'horizontal');
      this.set(`previousScrollToX`, newScrollLeft);
    } else if (newScrollTop !== this.get('previousScrollToY')) {
      this.get('onScroll')(e, newScrollTop, 'vertical');
      this.set(`previousScrollToY`, newScrollTop);
    }
  },

  /**
   * Sets the scroll property (scrollTop, or scrollLeft) for the given the direction and offset.
   *
   * @method scrollToPosition
   * @private
   * @param offset  Number -- offset amount in pixels
   * @param direction String -- 'X' | 'Y' -- indicates what direction is being scrolled
   */
  scrollToPosition(offset, direction) {
    offset = Number.parseInt(offset, 10);

    if (Number.isNaN(offset)) {
      return;
    }
    const scrollOffsetAttr = direction === 'X' ? 'scrollLeft' : 'scrollTop';
    this.$()[scrollOffsetAttr](offset);
  },

  configureInitialScrollPosition() {
    this.scrollToPosition(this.get('scrollToX'), 'X');
    this.scrollToPosition(this.get('scrollToY'), 'Y');
  },

  didInsertElement() {
    this._super(...arguments);
    this.addEventListener(this.$()[0], 'scroll', (e) => {
      this.scrolled(e);
    });
    this.configureInitialScrollPosition();
  },

  didReceiveAttrs() {
    // Sync property changes to `scrollToX` and `scrollToY` with the `scrollTop` and `scrollLeft` attributes
    // of the rendered DOM element.
    ['X', 'Y'].forEach((direction) => {
      const oldOffset = this.get(`previousScrollTo${direction}`);
      const newOffset = this.get(`scrollTo${direction}`);

      if (oldOffset !== newOffset) {
        schedule('afterRender', this, this.scrollToPosition, newOffset, direction);
      }
    });
  }

});

<|endoftext|>


<commit_before>/**
 * @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
 */
openerp.base.list.editable = function (openerp) {
    var KEY_RETURN = 13,
        KEY_ESCAPE = 27;

    // editability status of list rows
    openerp.base.ListView.prototype.defaults.editable = null;

    var old_init = openerp.base.ListView.prototype.init,
        old_actual_search = openerp.base.ListView.prototype.do_actual_search,
        old_add_record = openerp.base.ListView.prototype.do_add_record,
        old_on_loaded = openerp.base.ListView.prototype.on_loaded;
    // TODO: not sure second @lends on existing item is correct, to check
    _.extend(openerp.base.ListView.prototype, /** @lends openerp.base.ListView# */{
        init: function () {
            var self = this;
            old_init.apply(this, arguments);
            $(this.groups).bind({
                'edit': function (e, id, dataset) {
                    self.do_edit(dataset.index, id, dataset);
                },
                'saved': function () {
                    if (self.groups.get_selection().length) {
                        return;
                    }
                    self.compute_aggregates();
                }
            })
        },
        /**
         * Handles the activation of a record in editable mode (making a record
         * editable), called *after* the record has become editable.
         *
         * The default behavior is to setup the listview's dataset to match
         * whatever dataset was provided by the editing List
         *
         * @param {Number} index index of the record in the dataset
         * @param {Object} id identifier of the record being edited
         * @param {openerp.base.DataSet} dataset dataset in which the record is available
         */
        do_edit: function (index, id, dataset) {
            _.extend(this.dataset, dataset);
        },
        /**
         * Sets editability status for the list, based on defaults, view
         * architecture and the provided flag, if any.
         *
         * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom".
         */
        set_editable: function (force) {
            // If ``force``, set editability to bottom
            // otherwise rely on view default
            // view' @editable is handled separately as we have not yet
            // fetched and processed the view at this point.
            this.options.editable = (
                    (force && "bottom")
                    || this.defaults.editable);
        },
        /**
         * Replace do_actual_search to handle editability process
         */
        do_actual_search: function (results) {
            this.set_editable(results.context['set_editable']);
            old_actual_search.call(this, results);
        },
        /**
         * Replace do_add_record to handle editability (and adding new record
         * as an editable row at the top or bottom of the list)
         */
        do_add_record: function () {
            if (this.options.editable) {
                this.groups.new_record();
            } else {
                old_add_record.call(this);
            }
        },
        on_loaded: function (data, grouped) {
            // tree/@editable takes priority on everything else if present.
            this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable;
            return old_on_loaded.call(this, data, grouped);
        }
    });

    _.extend(openerp.base.ListView.Groups.prototype, /** @lends openerp.base.ListView.Groups# */{
        passtrough_events: openerp.base.ListView.Groups.prototype.passtrough_events + " edit saved",
        new_record: function () {
            // TODO: handle multiple children
            this.children[null].new_record();
        }
    });

    var old_list_row_clicked = openerp.base.ListView.List.prototype.row_clicked;
    _.extend(openerp.base.ListView.List.prototype, /** @lends openerp.base.ListView.List */{
        row_clicked: function (event) {
            if (!this.options.editable) {
                return old_list_row_clicked.call(this, event);
            }
            this.edit_record();
        },
        /**
         * Checks if a record is being edited, and if so cancels it
         */
        cancel_pending_edition: function () {
            if (!this.edition) {
                return;
            }

            if (this.edition_index !== null) {
                this.reload_record(this.edition_index);
            }
            this.edition_form.stop();
            this.edition_form.$element.remove();
            delete this.edition_form;
            delete this.edition_index;
            delete this.edition;
        },
        render_row_as_form: function (row) {
            this.cancel_pending_edition();

            var self = this;
            var $new_row = $('<tr>', {
                    id: _.uniqueId('oe-editable-row-'),
                    'class': $(row).attr('class'),
                    onclick: function (e) {e.stopPropagation();}
                })
                .keyup(function (e) {
                    switch (e.which) {
                        case KEY_RETURN:
                            self.save_row(true);
                            break;
                        case KEY_ESCAPE:
                            self.cancel_edition();
                            break;
                        default:
                            return;
                    }
                })
                .delegate('button.oe-edit-row-save', 'click', function () {
                    self.save_row();
                })
                .delegate('button.oe-edit-row-cancel', 'click', function () {
                    self.cancel_edition();
                });
            if (row) {
                $new_row.replaceAll(row);
            } else if (this.options.editable === 'top') {
                this.$current.prepend($new_row);
            } else if (this.options.editable) {
                this.$current.append($new_row);
            }
            this.edition = true;
            this.edition_index = this.dataset.index;
            this.edition_form = _.extend(new openerp.base.FormView(
                    null, this.group.view.session, $new_row.attr('id'),
                    this.dataset, false), {
                template: 'ListView.row.form',
                registry: openerp.base.list.form.widgets
            });
            this.edition_form.on_loaded({fields_view: this.get_fields_view()});
            this.edition_form.on_record_loaded.add({
                position: 'last',
                unique: true,
                callback: function () {
                    var $e = self.edition_form.$element;
                    $e.find('td')
                          .addClass('oe-field-cell')
                          .removeAttr('width')
                      .end()
                      .find('td:first').removeClass('oe-field-cell').end()
                      .find('td:last').removeClass('oe-field-cell').end();
                    _(self.columns).each(function (column) {
                        if (column.meta) {
                            $e.prepend('<td>');
                        }
                    });
                }
            });
            this.edition_form.do_show();
        },
        /**
         * Saves the current row, and triggers the edition of its following
         * sibling if asked.
         *
         * @param {Boolean} [edit_next=false] should the next row become editable
         */
        save_row: function (edit_next) {
            var self = this;
            this.edition_form.do_save(function (result) {
                self.reload_record(self.dataset.index, true).then(function () {
                    self.edition_form.stop();
                    delete self.edition_form;
                    delete self.edition_index;
                    delete self.edition;

                    $(self).trigger('saved', [self.dataset]);
                    if (!edit_next) {
                        return;
                    }
                    if (result.created) {
                        self.new_record();
                        return;
                    }
                    self.dataset.next();
                    self.edit_record();
                });
            }, this.options.editable === 'top');
        },
        /**
         * Cancels the edition of the row for the current dataset index
         */
        cancel_edition: function () {
            this.cancel_pending_edition();
        },
        /**
         * Edits record currently selected via dataset
         */
        edit_record: function () {
            this.render_row_as_form(
                this.$current.children(
                    _.sprintf('[data-index=%d]',
                            this.dataset.index)));
            $(this).trigger(
                'edit',
                [this.rows[this.dataset.index].data.id.value, this.dataset]);
        },
        new_record: function () {
            this.dataset.index = null;
            this.render_row_as_form();
        }
    });
    openerp.base.list = {form: {}};
    openerp.base.list.form.WidgetFrame = openerp.base.form.WidgetFrame.extend({
        template: 'ListView.row.frame'
    });
    var form_widgets = openerp.base.form.widgets;
    openerp.base.list.form.widgets = form_widgets.clone({
        'frame': 'openerp.base.list.form.WidgetFrame'
    });
    // All form widgets inherit a problematic behavior from
    // openerp.base.form.WidgetFrame: the cell itself is removed when invisible
    // whether it's @invisible or @attrs[invisible]. In list view, only the
    // former should completely remove the cell. We need to override update_dom
    // on all widgets since we can't just hit on widget itself (I think)
    var list_form_widgets = openerp.base.list.form.widgets;
    _(list_form_widgets.map).each(function (widget_path, key) {
        if (key === 'frame') { return; }
        var new_path = 'openerp.base.list.form.' + key;

        openerp.base.list.form[key] = (form_widgets.get_object(key)).extend({
            update_dom: function () {
                this.$element.children().css('visibility', '');
                if (this.invisible && this.node.attrs.invisible !== '1') {
                    this.$element.children().css('visibility', 'hidden');
                } else {
                    this._super();
                }
            }
        });
        list_form_widgets.add(key, new_path);
    });
};
<commit_msg>[IMP] don't wait for the bloody record to be fully loaded to fixup cell styles and add groupby columns (in case of grouping), it makes the list titles jittery which looks terrible. Instead, can fixup the row right after rendering, which makes the whole thing much stabler<commit_after>/**
 * @namespace handles editability case for lists, because it depends on form and forms already depends on lists it had to be split out
 */
openerp.base.list.editable = function (openerp) {
    var KEY_RETURN = 13,
        KEY_ESCAPE = 27;

    // editability status of list rows
    openerp.base.ListView.prototype.defaults.editable = null;

    var old_init = openerp.base.ListView.prototype.init,
        old_actual_search = openerp.base.ListView.prototype.do_actual_search,
        old_add_record = openerp.base.ListView.prototype.do_add_record,
        old_on_loaded = openerp.base.ListView.prototype.on_loaded;
    // TODO: not sure second @lends on existing item is correct, to check
    _.extend(openerp.base.ListView.prototype, /** @lends openerp.base.ListView# */{
        init: function () {
            var self = this;
            old_init.apply(this, arguments);
            $(this.groups).bind({
                'edit': function (e, id, dataset) {
                    self.do_edit(dataset.index, id, dataset);
                },
                'saved': function () {
                    if (self.groups.get_selection().length) {
                        return;
                    }
                    self.compute_aggregates();
                }
            })
        },
        /**
         * Handles the activation of a record in editable mode (making a record
         * editable), called *after* the record has become editable.
         *
         * The default behavior is to setup the listview's dataset to match
         * whatever dataset was provided by the editing List
         *
         * @param {Number} index index of the record in the dataset
         * @param {Object} id identifier of the record being edited
         * @param {openerp.base.DataSet} dataset dataset in which the record is available
         */
        do_edit: function (index, id, dataset) {
            _.extend(this.dataset, dataset);
        },
        /**
         * Sets editability status for the list, based on defaults, view
         * architecture and the provided flag, if any.
         *
         * @param {Boolean} [force] forces the list to editability. Sets new row edition status to "bottom".
         */
        set_editable: function (force) {
            // If ``force``, set editability to bottom
            // otherwise rely on view default
            // view' @editable is handled separately as we have not yet
            // fetched and processed the view at this point.
            this.options.editable = (
                    (force && "bottom")
                    || this.defaults.editable);
        },
        /**
         * Replace do_actual_search to handle editability process
         */
        do_actual_search: function (results) {
            this.set_editable(results.context['set_editable']);
            old_actual_search.call(this, results);
        },
        /**
         * Replace do_add_record to handle editability (and adding new record
         * as an editable row at the top or bottom of the list)
         */
        do_add_record: function () {
            if (this.options.editable) {
                this.groups.new_record();
            } else {
                old_add_record.call(this);
            }
        },
        on_loaded: function (data, grouped) {
            // tree/@editable takes priority on everything else if present.
            this.options.editable = data.fields_view.arch.attrs.editable || this.options.editable;
            return old_on_loaded.call(this, data, grouped);
        }
    });

    _.extend(openerp.base.ListView.Groups.prototype, /** @lends openerp.base.ListView.Groups# */{
        passtrough_events: openerp.base.ListView.Groups.prototype.passtrough_events + " edit saved",
        new_record: function () {
            // TODO: handle multiple children
            this.children[null].new_record();
        }
    });

    var old_list_row_clicked = openerp.base.ListView.List.prototype.row_clicked;
    _.extend(openerp.base.ListView.List.prototype, /** @lends openerp.base.ListView.List */{
        row_clicked: function (event) {
            if (!this.options.editable) {
                return old_list_row_clicked.call(this, event);
            }
            this.edit_record();
        },
        /**
         * Checks if a record is being edited, and if so cancels it
         */
        cancel_pending_edition: function () {
            if (!this.edition) {
                return;
            }

            if (this.edition_index !== null) {
                this.reload_record(this.edition_index);
            }
            this.edition_form.stop();
            this.edition_form.$element.remove();
            delete this.edition_form;
            delete this.edition_index;
            delete this.edition;
        },
        render_row_as_form: function (row) {
            this.cancel_pending_edition();

            var self = this;
            var $new_row = $('<tr>', {
                    id: _.uniqueId('oe-editable-row-'),
                    'class': $(row).attr('class'),
                    onclick: function (e) {e.stopPropagation();}
                })
                .keyup(function (e) {
                    switch (e.which) {
                        case KEY_RETURN:
                            self.save_row(true);
                            break;
                        case KEY_ESCAPE:
                            self.cancel_edition();
                            break;
                        default:
                            return;
                    }
                })
                .delegate('button.oe-edit-row-save', 'click', function () {
                    self.save_row();
                })
                .delegate('button.oe-edit-row-cancel', 'click', function () {
                    self.cancel_edition();
                });
            if (row) {
                $new_row.replaceAll(row);
            } else if (this.options.editable === 'top') {
                this.$current.prepend($new_row);
            } else if (this.options.editable) {
                this.$current.append($new_row);
            }
            this.edition = true;
            this.edition_index = this.dataset.index;
            this.edition_form = _.extend(new openerp.base.FormView(
                    null, this.group.view.session, $new_row.attr('id'),
                    this.dataset, false), {
                template: 'ListView.row.form',
                registry: openerp.base.list.form.widgets
            });
            $.when(this.edition_form.on_loaded({fields_view: this.get_fields_view()})).then(function () {
                // put in $.when just in case  FormView.on_loaded becomes asynchronous
                $new_row.find('td')
                      .addClass('oe-field-cell')
                      .removeAttr('width')
                  .end()
                  .find('td:first').removeClass('oe-field-cell').end()
                  .find('td:last').removeClass('oe-field-cell').end();
                // pad in case of groupby
                _(self.columns).each(function (column) {
                    if (column.meta) {
                        $new_row.prepend('<td>');
                    }
                });

                self.edition_form.do_show();
            });
        },
        /**
         * Saves the current row, and triggers the edition of its following
         * sibling if asked.
         *
         * @param {Boolean} [edit_next=false] should the next row become editable
         */
        save_row: function (edit_next) {
            var self = this;
            this.edition_form.do_save(function (result) {
                self.reload_record(self.dataset.index, true).then(function () {
                    self.edition_form.stop();
                    delete self.edition_form;
                    delete self.edition_index;
                    delete self.edition;

                    $(self).trigger('saved', [self.dataset]);
                    if (!edit_next) {
                        return;
                    }
                    if (result.created) {
                        self.new_record();
                        return;
                    }
                    self.dataset.next();
                    self.edit_record();
                });
            }, this.options.editable === 'top');
        },
        /**
         * Cancels the edition of the row for the current dataset index
         */
        cancel_edition: function () {
            this.cancel_pending_edition();
        },
        /**
         * Edits record currently selected via dataset
         */
        edit_record: function () {
            this.render_row_as_form(
                this.$current.children(
                    _.sprintf('[data-index=%d]',
                            this.dataset.index)));
            $(this).trigger(
                'edit',
                [this.rows[this.dataset.index].data.id.value, this.dataset]);
        },
        new_record: function () {
            this.dataset.index = null;
            this.render_row_as_form();
        }
    });
    openerp.base.list = {form: {}};
    openerp.base.list.form.WidgetFrame = openerp.base.form.WidgetFrame.extend({
        template: 'ListView.row.frame'
    });
    var form_widgets = openerp.base.form.widgets;
    openerp.base.list.form.widgets = form_widgets.clone({
        'frame': 'openerp.base.list.form.WidgetFrame'
    });
    // All form widgets inherit a problematic behavior from
    // openerp.base.form.WidgetFrame: the cell itself is removed when invisible
    // whether it's @invisible or @attrs[invisible]. In list view, only the
    // former should completely remove the cell. We need to override update_dom
    // on all widgets since we can't just hit on widget itself (I think)
    var list_form_widgets = openerp.base.list.form.widgets;
    _(list_form_widgets.map).each(function (widget_path, key) {
        if (key === 'frame') { return; }
        var new_path = 'openerp.base.list.form.' + key;

        openerp.base.list.form[key] = (form_widgets.get_object(key)).extend({
            update_dom: function () {
                this.$element.children().css('visibility', '');
                if (this.invisible && this.node.attrs.invisible !== '1') {
                    this.$element.children().css('visibility', 'hidden');
                } else {
                    this._super();
                }
            }
        });
        list_form_widgets.add(key, new_path);
    });
};
<|endoftext|>


<commit_before>openerp.base_kanban = function (openerp) {
QWeb.add_template('/base_kanban/static/src/xml/base_kanban.xml');
openerp.base.views.add('kanban', 'openerp.base_kanban.KanbanView');
openerp.base_kanban.KanbanView = openerp.base.View.extend({

    init: function (parent, element_id, dataset, view_id) {
        this._super(parent, element_id);
        this.view_manager = parent;
        this.dataset = dataset;
        this.domain = dataset.domain;
        this.context = dataset.context;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.group_by_field = false;
        this.source_index = {};
        this.all_display_data = false;
        this.groups = [];
    },
    start: function () {
        this.rpc("/base_kanban/kanbanview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function (data) {
        var self = this;
        this.template_xml = '';
        this.columns = data.all_fields;
        _.each(data.fields_view.arch.children, function(child) {
            if (child.tag == "template"){
                self.template_xml = openerp.base.json_node_to_xml(child, true);
            }
        });
        if (this.template_xml) {
            self.dataset.read_slice([], {
                context: self.dataset.get_context(),
                domain: self.dataset.get_domain()}, function (records) {
                self.all_display_data = [{'records': records, 'value':false, 'header': false, 'ids': self.dataset.ids}];
                self.on_show_data(self.all_display_data);
            });
        }
    },
    on_show_data: function (datas) {
        var self = this;
        var new_qweb = new QWeb2.Engine();
        self.$element.html(QWeb.render("KanbanBiew", {"datas" :datas}));

        this.on_reload_kanban();
        var drag_handel = false;
        if (this.$element.find(".oe-kanban-draghandle").length > 0) {
            drag_handel = ".oe-kanban-draghandle";
        }
        this.$element.find(".oe_column").sortable({
            connectWith: ".oe_column",
            handle : drag_handel,
            start: function(event, ui) {
                self.source_index['index'] = ui.item.index();
                self.source_index['column'] = ui.item.parent().attr('id');
            },
            stop: self.on_recieve_record,
        });
        this.$element.find(".record").addClass( "ui-widget ui-widget-content ui-corner-all" )
        this.$element.find(".oe_column").disableSelection()
        this.$element.find('button.oe_kanban_button_new').click(this.do_add_record);
    },
    on_button_click: function (button_attrs, record_id) {
        var self = this;
        if (this.groups.length) {
            _.each(this.groups, function (group) {
                group.list([],
                    function (groups) {},
                    function (dataset) {
                        dataset.read_slice([], {}, function(records) {
                            var index = parseInt(_.indexOf(dataset.ids, record_id));
                            if(index >= 0) {
                                self.on_confirm_click(dataset, button_attrs, index, record_id);
                            }
                        });
                    }
                );
            });
        } else {
            var index = parseInt(_.indexOf(self.dataset.ids, record_id));
            if (index >= 0) {
                _.extend(self.dataset, {domain: self.domain, context: self.context});
                self.on_confirm_click(self.dataset, button_attrs, index, record_id);
            }
        }
    },
    on_confirm_click: function (dataset, button_attrs, index, record_id) {
        if (button_attrs.type == 'edit') {
            this.do_edit_record(dataset, index);
        } else {
            this.on_execute_button_click(dataset, button_attrs, record_id);
        }
    },
    do_add_record: function () {
        this.do_edit_record(this.dataset, null);
    },
    do_edit_record: function (dataset, index) {
        var self = this;
        _.extend(this.dataset, {
            domain: dataset.domain,
            context: dataset.get_context()
        }).read_slice([], {}, function () {
            self.dataset.index = index;
            self.do_switch_view('form');
        });
    },
    do_delete: function (id) {
        var self = this;
        return $.when(this.dataset.unlink([id])).then(function () {
            self.drop_records(id);
        });
    },
    drop_records: function (id) {
        var self = this;
        _.each(self.all_display_data, function(data, index) {
            _.each(data.records, function(record, index_row) {
                if (parseInt(record.id) == id) {
                    self.all_display_data[index]['records'].splice(index_row, 1);
                    self.all_display_data[index]['ids'].splice(index_row, 1);
                    return false;
                }
            });
        });
        self.$element.find("#main_" + id).remove();
    },
    on_execute_button_click: function (dataset, button_attrs, record_id) {
        var self = this;
        this.execute_action(
            button_attrs, dataset,
            record_id, function () {
                var count = 1;
                _.each(self.all_display_data, function(data, index) {
                    self.dataset.read_ids( data.ids, [], function(records){
                        self.all_display_data[index].records = records;
                        if(self.all_display_data.length == count) {
                            self.on_reload_kanban();
                        }
                        count++;
                    });
                });
            }
        );
    },
    on_recieve_record: function (event, ui) {
        var self = this;
        var from = ui.item.index();
        var search_action = false;
        var to = ui.item.prev().index() || 0;
        if (!ui.item.attr("id")) {
            return false;
        }
        if (self.columns.sequence && (self.source_index.index >= 0 && self.source_index.index != from) ||
                (self.source_index.column && self.source_index.column != ui.item.parent().attr('id'))) {
            var child_record = ui.item.parent().children();
            var data, sequence = 1, index = to;
            child_record.splice(0, to);
            var flag = false;
            if (to >= 0 && child_record) {
                var record_id = parseInt($(child_record).attr("id").split("_")[1]);
                if (record_id) {
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
	                        if(record_id == record.id && record.sequence) {
	                            sequence = record.sequence;
	                            flag = true;
	                            return false;
	                        }
                        });
                        if(flag) {return false;}
                    });
                }
            }
            _.each(child_record, function (child) {
                var child_id = parseInt($(child).attr("id").split("_")[1]);
                if (child_id) {
                    flag = false;
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
                            if(parseInt(record.id) == child_id) {
                                self.all_display_data[index]['records'][index_row]['sequence'] = sequence;
                                flag = true;
                                return false;
                            }
                        });
                        if (flag) {return false;}
                    });
                    self.dataset.write(child_id, {sequence: sequence});
                    sequence++;
                    search_action = true;
                }
            });
        }
        if (self.group_by_field && self.source_index.column && self.source_index.column != ui.item.parent().attr('id')) {
            var value = ui.item.closest("td").attr("id");
            if (value) {
                var data_val = {};
                var wirte_id = parseInt(ui.item.attr("id").split("_")[1]);
                value = value.split("_")[1];
                if (value == 'false') {
                    value = false;
                }
                var update_record = false;
                _.each(self.all_display_data, function(data, index) {
                    _.each(data.records, function(record, index_row) {
                        if(parseInt(record.id) == wirte_id) {
                            self.all_display_data[index]['records'][index_row][self.group_by_field] = value;
                            update_record = self.all_display_data[index]['records'].splice(index_row,1)
                            return false;
                        }
                    });
                    if (update_record) {return false;}
                });
                _.each(self.all_display_data, function(data, index) {
                    if (data.value == value || (data.value == 'false' && value == false)) {
                        self.all_display_data[index]['records'].push(update_record[0]);
                    }
                });
                data_val[self.group_by_field] = value;
                self.dataset.write(wirte_id, data_val);
                search_action = true;
            }
        }
        if (search_action) {
            self.on_reload_kanban();
        }
        this.source_index = {};
    },
    on_reload_kanban: function (){
        var self = this;
        var new_qweb = new QWeb2.Engine();
        new_qweb.add_template('<templates><t t-name="custom_template">' + this.template_xml + '</t></templates>');
        _.each(self.all_display_data, function(data, index) {
            if (data.records.length > 0){
                _.each(data.records, function(record) {
                    self.$element.find("#main_" + record.id).children().remove();
                    self.$element.find("#main_" + record.id).append(new_qweb.render('custom_template', record));
                });
            } else {
                self.$element.find("#column_" + data.value).remove();
                self.all_display_data.splice(index, 1);
            }
        });
        this.$element.find( ".oe_table_column " ).css("width", 99 / self.all_display_data.length +"%");
        this.$element.find('button').click(function() {
            var record_id = $(this).closest(".record").attr("id");
            if (record_id) {
                record_id = parseInt(record_id.split("_")[1])
                if (record_id) {
                    if ($(this).data("type") == "delete") {
                        self.do_delete(record_id);
                    } else {
                        var button_attrs = $(this).data()
                        self.on_button_click(button_attrs, record_id);
                    }
                }
            }
        });
    },

    do_search: function (domains, contexts, group_by) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: group_by
        }, function (results) {
            self.group_by_field = false;
            self.datagroup = new openerp.base.DataGroup(self, self.model, results.domain, results.context, results.group_by || []);
            self.dataset.context = results.context;
            self.dataset.domain = results.domain;
            self.datagroup.list([],
                function (groups) {
                    self.groups = groups;
                    if (group_by.length >= 1) {
                        self.group_by_field = group_by[0].group_by;
                        self.do_render_group(groups);
                    }
                },
                function (dataset) {
                    self.domain = dataset.domain;
                    self.context = dataset.context;
                    self.groups = [];
                    self.dataset.read_slice([], {}, function(records) {
                        self.all_display_data = [{'records': records, 'value':false, 'header' : false, 'ids': self.dataset.ids}];
                        self.$element.find("#kanbanview").remove();
                        self.on_show_data(self.all_display_data);
                    });
                }
            );

        });
    },
    do_render_group : function (datagroups) {
        this.all_display_data = [];
        var self = this;
        _.each(datagroups, function (group) {
            self.dataset.context = group.context;
            self.dataset.domain = group.domain;
            var group_name = group.value;
            var group_value = group.value;
            if (!group.value) {
                group_name = "Undefined";
                group_value = 'false';
            } else if (group.value instanceof Array) {
                group_name = group.value[1];
                group_value = group.value[0];
            }
            self.dataset.read_slice([], {}, function(records) {
                self.all_display_data.push({"value" : group_value, "records": records, 'header':group_name, 'ids': self.dataset.ids});
                if (datagroups.length == self.all_display_data.length) {
                    self.$element.find("#kanbanview").remove();
                    self.on_show_data(self.all_display_data);
                }
            });
        });
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[IMP] kanban view :- improve button click method and serach method. <commit_after>openerp.base_kanban = function (openerp) {
QWeb.add_template('/base_kanban/static/src/xml/base_kanban.xml');
openerp.base.views.add('kanban', 'openerp.base_kanban.KanbanView');
openerp.base_kanban.KanbanView = openerp.base.View.extend({

    init: function (parent, element_id, dataset, view_id) {
        this._super(parent, element_id);
        this.view_manager = parent;
        this.dataset = dataset;
        this.domain = dataset.domain;
        this.context = dataset.context;
        this.model = this.dataset.model;
        this.view_id = view_id;
        this.group_by = [];
        this.group_by_field = false;
        this.source_index = {};
        this.all_display_data = false;
        this.groups = [];
    },
    start: function () {
        this.rpc("/base_kanban/kanbanview/load",
        {"model": this.model, "view_id": this.view_id}, this.on_loaded);
    },
    on_loaded: function (data) {
        var self = this;
        this.template_xml = '';
        this.columns = data.all_fields;
        _.each(data.fields_view.arch.children, function(child) {
            if (child.tag == "template"){
                self.template_xml = openerp.base.json_node_to_xml(child, true);
            }
        });
        if (this.template_xml) {
            self.dataset.read_slice([], {
                context: self.dataset.get_context(),
                domain: self.dataset.get_domain()}, function (records) {
                self.all_display_data = [{'records': records, 'value':false, 'header': false, 'ids': self.dataset.ids}];
                self.on_show_data(self.all_display_data);
            });
        }
    },
    on_show_data: function (datas) {
        var self = this;
        var new_qweb = new QWeb2.Engine();
        self.$element.html(QWeb.render("KanbanBiew", {"datas" :datas}));

        this.on_reload_kanban();
        var drag_handel = false;
        if (this.$element.find(".oe-kanban-draghandle").length > 0) {
            drag_handel = ".oe-kanban-draghandle";
        }
        this.$element.find(".oe_column").sortable({
            connectWith: ".oe_column",
            handle : drag_handel,
            start: function(event, ui) {
                self.source_index['index'] = ui.item.index();
                self.source_index['column'] = ui.item.parent().attr('id');
            },
            stop: self.on_recieve_record,
        });
        this.$element.find(".record").addClass( "ui-widget ui-widget-content ui-corner-all" )
        this.$element.find(".oe_column").disableSelection()
        this.$element.find('button.oe_kanban_button_new').click(this.do_add_record);
    },
    on_button_click: function (button_attrs, record_id) {
        var self = this;
        if (this.groups.length) {
            _.each(this.groups, function (group) {
                group.list([],
                    function (groups) {},
                    function (dataset) {
                        dataset.read_slice([], {}, function(records) {
                            var index = parseInt(_.indexOf(dataset.ids, record_id));
                            if(index >= 0) {
                                self.on_confirm_click(dataset, button_attrs, index, record_id);
                            }
                        });
                    }
                );
            });
        } else {
            var index = parseInt(_.indexOf(self.dataset.ids, record_id));
            if (index >= 0) {
                _.extend(self.dataset, {domain: self.domain, context: self.context});
                self.on_confirm_click(self.dataset, button_attrs, index, record_id);
            }
        }
    },
    on_confirm_click: function (dataset, button_attrs, index, record_id) {
        if (button_attrs.type == 'edit') {
            this.do_edit_record(dataset, index);
        } else {
            this.on_execute_button_click(dataset, button_attrs, record_id);
        }
    },
    do_add_record: function () {
        this.do_edit_record(this.dataset, null);
    },
    do_edit_record: function (dataset, index) {
        var self = this;
        _.extend(this.dataset, {
            domain: dataset.domain,
            context: dataset.get_context()
        }).read_slice([], {}, function () {
            self.dataset.index = index;
            self.do_switch_view('form');
        });
    },
    do_delete: function (id) {
        var self = this;
        return $.when(this.dataset.unlink([id])).then(function () {
            self.drop_records(id);
        });
    },
    drop_records: function (id) {
        var self = this;
        _.each(self.all_display_data, function(data, index) {
            _.each(data.records, function(record, index_row) {
                if (parseInt(record.id) == id) {
                    self.all_display_data[index]['records'].splice(index_row, 1);
                    self.all_display_data[index]['ids'].splice(index_row, 1);
                    return false;
                }
            });
        });
        self.$element.find("#main_" + id).remove();
    },
    on_execute_button_click: function (dataset, button_attrs, record_id) {
        var self = this;
        this.execute_action(
            button_attrs, dataset,
            record_id, function () {
                var count = 1;
                _.each(self.all_display_data, function(data, index) {
                    self.dataset.read_ids( data.ids, [], function(records){
                        self.all_display_data[index].records = records;
                        if(self.all_display_data.length == count) {
                            self.do_actual_search();
                        }
                        count++;
                    });
                });
            }
        );
    },
    on_recieve_record: function (event, ui) {
        var self = this;
        var from = ui.item.index();
        var search_action = false;
        var to = ui.item.prev().index() || 0;
        if (!ui.item.attr("id")) {
            return false;
        }
        if (self.columns.sequence && (self.source_index.index >= 0 && self.source_index.index != from) ||
                (self.source_index.column && self.source_index.column != ui.item.parent().attr('id'))) {
            var child_record = ui.item.parent().children();
            var data, sequence = 1, index = to;
            child_record.splice(0, to);
            var flag = false;
            if (to >= 0 && child_record) {
                var record_id = parseInt($(child_record).attr("id").split("_")[1]);
                if (record_id) {
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
                            if(record_id == record.id && record.sequence) {
                                sequence = record.sequence;
                                flag = true;
                                return false;
                            }
                        });
                        if(flag) {return false;}
                    });
                }
            }
            _.each(child_record, function (child) {
                var child_id = parseInt($(child).attr("id").split("_")[1]);
                if (child_id) {
                    flag = false;
                    _.each(self.all_display_data, function(data, index) {
                        _.each(data.records, function(record, index_row) {
                            if(parseInt(record.id) == child_id) {
                                self.all_display_data[index]['records'][index_row]['sequence'] = sequence;
                                flag = true;
                                return false;
                            }
                        });
                        if (flag) {return false;}
                    });
                    self.dataset.write(child_id, {sequence: sequence});
                    sequence++;
                    search_action = true;
                }
            });
        }
        if (self.group_by_field && self.source_index.column && self.source_index.column != ui.item.parent().attr('id')) {
            var value = ui.item.closest("td").attr("id");
            if (value) {
                var data_val = {};
                var wirte_id = parseInt(ui.item.attr("id").split("_")[1]);
                value = value.split("_")[1];
                if (value == 'false') {
                    value = false;
                }
                var update_record = false;
                _.each(self.all_display_data, function(data, index) {
                    _.each(data.records, function(record, index_row) {
                        if(parseInt(record.id) == wirte_id) {
                            self.all_display_data[index]['records'][index_row][self.group_by_field] = value;
                            update_record = self.all_display_data[index]['records'].splice(index_row,1)
                            return false;
                        }
                    });
                    if (update_record) {return false;}
                });
                _.each(self.all_display_data, function(data, index) {
                    if (data.value == value || (data.value == 'false' && value == false)) {
                        self.all_display_data[index]['records'].push(update_record[0]);
                    }
                });
                data_val[self.group_by_field] = value;
                self.dataset.write(wirte_id, data_val);
                search_action = true;
            }
        }
        if (search_action) {
            self.on_reload_kanban();
        }
        this.source_index = {};
    },
    on_reload_kanban: function (){
        var self = this;
        var new_qweb = new QWeb2.Engine();
        new_qweb.add_template('<templates><t t-name="custom_template">' + this.template_xml + '</t></templates>');
        _.each(self.all_display_data, function(data, index) {
            if (data.records.length > 0){
                _.each(data.records, function(record) {
                    self.$element.find("#main_" + record.id).children().remove();
                    self.$element.find("#main_" + record.id).append(new_qweb.render('custom_template', record));
                });
            } else {
                self.$element.find("#column_" + data.value).remove();
                self.all_display_data.splice(index, 1);
            }
        });
        this.$element.find( ".oe_table_column " ).css("width", 99 / self.all_display_data.length +"%");
        this.$element.find('button').click(function() {
            var record_id = $(this).closest(".record").attr("id");
            if (record_id) {
                record_id = parseInt(record_id.split("_")[1])
                if (record_id) {
                    if ($(this).data("type") == "delete") {
                        self.do_delete(record_id);
                    } else {
                        var button_attrs = $(this).data()
                        self.on_button_click(button_attrs, record_id);
                    }
                }
            }
        });
    },

    do_search: function (domains, contexts, group_by) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: group_by
        }, function (results) {
            self.domain = results.domain;
            self.context = results.context;
            self.group_by = results.group_by;
            self.do_actual_search();
        });
    },
    do_actual_search : function () {
        var self = this;
        self.group_by_field = false;
        self.datagroup = new openerp.base.DataGroup(self, self.model, self.domain, self.context, self.group_by || []);
        self.dataset.context = self.context;
        self.dataset.domain = self.domain;
        self.datagroup.list([],
            function (groups) {
                self.groups = groups;
                if (self.group_by.length >= 1) {
                    self.group_by_field = self.group_by[0].group_by;
                    self.do_render_group(groups);
                }
            },
            function (dataset) {
                self.domain = dataset.domain;
                self.context = dataset.context;
                self.groups = [];
                self.dataset.read_slice([], {}, function(records) {
                    self.all_display_data = [{'records': records, 'value':false, 'header' : false, 'ids': self.dataset.ids}];
                    self.$element.find("#kanbanview").remove();
                    self.on_show_data(self.all_display_data);
                });
            }
        );
    },
    do_render_group : function (datagroups) {
        this.all_display_data = [];
        var self = this;
        _.each(datagroups, function (group) {
            self.dataset.context = group.context;
            self.dataset.domain = group.domain;
            var group_name = group.value;
            var group_value = group.value;
            if (!group.value) {
                group_name = "Undefined";
                group_value = 'false';
            } else if (group.value instanceof Array) {
                group_name = group.value[1];
                group_value = group.value[0];
            }
            self.dataset.read_slice([], {}, function(records) {
                self.all_display_data.push({"value" : group_value, "records": records, 'header':group_name, 'ids': self.dataset.ids});
                if (datagroups.length == self.all_display_data.length) {
                    self.$element.find("#kanbanview").remove();
                    self.on_show_data(self.all_display_data);
                }
            });
        });
    },

    do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

});
};

// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>