{"action":"created","comment":{"url":"https://api.github.com/repos/etalab/udata-admin/pulls/comments/34760595","id":34760595,"diff_hunk":"@@ -29,90 +136,290 @@ define(['api', 'models/validator', 'vue'], function(API, validator, Vue) {\n      * @param  {Object} schema the schema to based empty values\n      * @return {Object}        the updated data object\n      */\n-    function empty(obj, schema) {\n+    empty() {\n+        var schema = this.__schema__\n         for (var key in schema.properties) {\n             if (schema.properties.hasOwnProperty(key)) {\n-                obj[key] = schema.required.indexOf(key) >= 0 ? null : undefined;\n+                this[key] = schema.required.indexOf(key) >= 0 ? null : undefined;\n             }\n         }\n-        return obj;\n+        return this;\n     }\n \n+    on_fetched(data) {\n+        for (let prop in data.obj) {\n+            let value = data.obj[prop];\n+            this._set(prop, value);\n+        }\n+        this.$emit('updated');\n+        this.loading = false;\n+    }\n \n     /**\n-     * A Swagger model base class\n+     * Perform a model validation given its schema\n+     * @return {Object} A TV4 validation descriptor.\n      */\n-    var Model = Vue.extend({\n-        /**\n-         * Declare bindable attributes from Swagger Specifications\n-         */\n-        data: function() {\n-            return empty({loading: false}, schema_for(this));\n-        },\n-        computed: {\n-            classname: function() {\n-                return classname(this);\n-            },\n-            schema: function() {\n-                return schema_for(this);\n-            }\n-        },\n-        methods: {\n-            on_fetched: function(data) {\n-                var schema = this.schema,\n-                    prop, value;\n-\n-                for (prop in data.obj) {\n-                    value = data.obj[prop];\n-                    this.$set(prop, value)\n-                }\n-                // this.modelize(data.obj);\n-                // $.extend(true, this.$data, data.obj);\n-                this.$emit('updated', this);\n-                this.$dispatch(this.constructor.name.toLowerCase() + ':updated', this);\n-                this.loading = false;\n-            },\n-            validate: function() {\n-                return validator.validateMultiple(this.$data, this.schema);\n-            },\n-            clear: function() {\n-                empty(this.$data, this.schema);\n-                return this;\n-            },\n-            /**\n-             * Set values from a Raw object given the schema.\n-             * @param  {Object} raw    The raw object\n-             */\n-            modelize: function(raw) {\n-                var schema = this.schema,\n-                    prop, value, def;\n-\n-                for (prop in raw) {\n-                    value = raw[prop];\n-                    def = schema.properties[prop];\n-                    // Nested object\n-                    if (def.hasOwnProperty('$ref')) {\n-                        var classname = def.$ref.replace('#/definitions/', '');\n-\n-                            // Model =\n-                        console.log('$ref', def.$ref);\n-                        console.log(classname);\n-                    }\n-                    // Array of models\n-                    else if (def.type == 'array' && def.items.hasOwnProperty('$ref')) {\n-                        console.log('items.$ref', def.items.$ref);\n-                        var classname = def.items.$ref.replace('#/definitions/', '');\n-                        console.log(classname);\n-                    }\n-                    // Default: affectation is enough\n-                    else {\n-                        this.$set(prop, value);\n-                    }\n-                }\n-            }\n+    validate() {\n+        return validator.validateMultiple(this, this.__schema__);\n+    }\n+\n+    /**\n+     * Empty the model\n+     * @return {Object} Return itself allowing to chain methods.\n+     */\n+    clear() {\n+        this.empty();\n+        return this;\n+    }\n+};\n+\n+\n+/**\n+ * A base class for unpaginated list\n+ */\n+export class List extends Base {\n+    constructor(options) {\n+        super();\n+        this.$options = options || {};\n+\n+        this.items = [];\n+        this.query = this.$options.query || {};\n+        this.loading = false;\n+    }\n+\n+    get data() {\n+        return this.items;\n+    }\n+\n+    /**\n+     * The class name\n+     * @return {[type]} [description]\n+     */\n+    get __class__() {\n+        return this.constructor.name\n+    }\n+\n+    /**\n+     * Fetch a paginated list.\n+     * @param  {[type]} options [description]\n+     * @return {[type]}         [description]\n+     */\n+    fetch(options) {\n+        options = Object.assign(this.query, options);\n+        this.loading = true;\n+        this.$api(this.$options.ns + '.' + this.$options.fetch, options, this.on_fetched);\n+        return this;\n+    }\n+\n+    on_fetched(data) {\n+        while (this.items.length > 0) {\n+            this.items.pop();\n+        }\n+        for (var i=0; i < data.obj.length; i++) {\n+            this.items.push(data.obj[i]);\n+        }\n+        this.$emit('updated', this);\n+        this.loading = false;\n+    }\n+\n+    /**\n+     * Get an item given its ID\n+     */\n+    by_id(id) {\n+        var filtered = this.items.filter(function(item) {\n+            return item.hasOwnProperty('id') && item.id === id;\n+        });\n+        return filtered.length === 1 ? filtered[0] : null;\n+    }\n+\n+    /**\n+     * Empty the list\n+     * @return {Object} Return itself allowing to chain methods.\n+     */\n+    clear() {\n+        this.items = [];\n+        this.$emit('updated');\n+        return this;\n+    }\n+};\n+\n+/**\n+ * A base class for server-side paginted list.\n+ */\n+export class ModelPage extends Model {\n+    constructor(options) {\n+        super(options);\n+        this.query = this.$options.query || {};\n+        this.loading = true;\n+        this.serverside = true;\n+    }\n+\n+    /**\n+     * Total amount of pages\n+     * @return {int}\n+     */\n+    get pages() {\n+        return Math.ceil(this.total / this.page_size);\n+    }\n+\n+    /**\n+     * Field name used for sorting\n+     * @return {string}\n+     */\n+    get sorted() {\n+        if (!this.query.sort) {\n+            return;\n+        }\n+        return this.query.sort[0] == '-'\n+            ? this.query.sort.substring(1, this.query.sort.length)\n+            : this.query.sort;\n+    }\n+\n+    /**\n+     * Wether the sort is reversed (descending) or not (ascending)\n+     * @return {boolean}\n+     */\n+    get reversed() {\n+        if (!this.query.sort) {\n+            return;\n+        }\n+        return this.query.sort[0] == '-';\n+    }\n+\n+    get has_search() {\n+        var op = API[this.$options.ns].operations[this.$options.fetch];\n+\n+        return op.parameters.filter(function(p) {","path":"js/models/base.js","position":379,"original_position":379,"commit_id":"d1b0569cdeef890ba81180397e8079f01cc19220","original_commit_id":"d1b0569cdeef890ba81180397e8079f01cc19220","user":{"login":"noirbizarre","id":15725,"avatar_url":"https://avatars.githubusercontent.com/u/15725?v=3","gravatar_id":"","url":"https://api.github.com/users/noirbizarre","html_url":"https://github.com/noirbizarre","followers_url":"https://api.github.com/users/noirbizarre/followers","following_url":"https://api.github.com/users/noirbizarre/following{/other_user}","gists_url":"https://api.github.com/users/noirbizarre/gists{/gist_id}","starred_url":"https://api.github.com/users/noirbizarre/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/noirbizarre/subscriptions","organizations_url":"https://api.github.com/users/noirbizarre/orgs","repos_url":"https://api.github.com/users/noirbizarre/repos","events_url":"https://api.github.com/users/noirbizarre/events{/privacy}","received_events_url":"https://api.github.com/users/noirbizarre/received_events","type":"User","site_admin":false},"body":"For the arrow function, I will adapt it.\r\nThis boolean is very usefull to automatically display a search field or not into datatables.vue.","created_at":"2015-07-16T07:04:11Z","updated_at":"2015-07-16T07:04:11Z","html_url":"https://github.com/etalab/udata-admin/pull/25#discussion_r34760595","pull_request_url":"https://api.github.com/repos/etalab/udata-admin/pulls/25","_links":{"self":{"href":"https://api.github.com/repos/etalab/udata-admin/pulls/comments/34760595"},"html":{"href":"https://github.com/etalab/udata-admin/pull/25#discussion_r34760595"},"pull_request":{"href":"https://api.github.com/repos/etalab/udata-admin/pulls/25"}}},"pull_request":{"url":"https://api.github.com/repos/etalab/udata-admin/pulls/25","id":40042108,"html_url":"https://github.com/etalab/udata-admin/pull/25","diff_url":"https://github.com/etalab/udata-admin/pull/25.diff","patch_url":"https://github.com/etalab/udata-admin/pull/25.patch","issue_url":"https://api.github.com/repos/etalab/udata-admin/issues/25","number":25,"state":"open","locked":false,"title":"ES6 Migration","user":{"login":"noirbizarre","id":15725,"avatar_url":"https://avatars.githubusercontent.com/u/15725?v=3","gravatar_id":"","url":"https://api.github.com/users/noirbizarre","html_url":"https://github.com/noirbizarre","followers_url":"https://api.github.com/users/noirbizarre/followers","following_url":"https://api.github.com/users/noirbizarre/following{/other_user}","gists_url":"https://api.github.com/users/noirbizarre/gists{/gist_id}","starred_url":"https://api.github.com/users/noirbizarre/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/noirbizarre/subscriptions","organizations_url":"https://api.github.com/users/noirbizarre/orgs","repos_url":"https://api.github.com/users/noirbizarre/repos","events_url":"https://api.github.com/users/noirbizarre/events{/privacy}","received_events_url":"https://api.github.com/users/noirbizarre/received_events","type":"User","site_admin":false},"body":"This PR start ES6 migration with models.","created_at":"2015-07-15T16:29:08Z","updated_at":"2015-07-16T07:04:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e74c99520f096d11b0bfd4c0f3cd8bd303c4b366","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/etalab/udata-admin/pulls/25/commits","review_comments_url":"https://api.github.com/repos/etalab/udata-admin/pulls/25/comments","review_comment_url":"https://api.github.com/repos/etalab/udata-admin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/etalab/udata-admin/issues/25/comments","statuses_url":"https://api.github.com/repos/etalab/udata-admin/statuses/d1b0569cdeef890ba81180397e8079f01cc19220","head":{"label":"etalab:es6-models","ref":"es6-models","sha":"d1b0569cdeef890ba81180397e8079f01cc19220","user":{"login":"etalab","id":5313610,"avatar_url":"https://avatars.githubusercontent.com/u/5313610?v=3","gravatar_id":"","url":"https://api.github.com/users/etalab","html_url":"https://github.com/etalab","followers_url":"https://api.github.com/users/etalab/followers","following_url":"https://api.github.com/users/etalab/following{/other_user}","gists_url":"https://api.github.com/users/etalab/gists{/gist_id}","starred_url":"https://api.github.com/users/etalab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etalab/subscriptions","organizations_url":"https://api.github.com/users/etalab/orgs","repos_url":"https://api.github.com/users/etalab/repos","events_url":"https://api.github.com/users/etalab/events{/privacy}","received_events_url":"https://api.github.com/users/etalab/received_events","type":"Organization","site_admin":false},"repo":{"id":32721062,"name":"udata-admin","full_name":"etalab/udata-admin","owner":{"login":"etalab","id":5313610,"avatar_url":"https://avatars.githubusercontent.com/u/5313610?v=3","gravatar_id":"","url":"https://api.github.com/users/etalab","html_url":"https://github.com/etalab","followers_url":"https://api.github.com/users/etalab/followers","following_url":"https://api.github.com/users/etalab/following{/other_user}","gists_url":"https://api.github.com/users/etalab/gists{/gist_id}","starred_url":"https://api.github.com/users/etalab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etalab/subscriptions","organizations_url":"https://api.github.com/users/etalab/orgs","repos_url":"https://api.github.com/users/etalab/repos","events_url":"https://api.github.com/users/etalab/events{/privacy}","received_events_url":"https://api.github.com/users/etalab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/etalab/udata-admin","description":"Admin/Backoffice for uData","fork":false,"url":"https://api.github.com/repos/etalab/udata-admin","forks_url":"https://api.github.com/repos/etalab/udata-admin/forks","keys_url":"https://api.github.com/repos/etalab/udata-admin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/etalab/udata-admin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/etalab/udata-admin/teams","hooks_url":"https://api.github.com/repos/etalab/udata-admin/hooks","issue_events_url":"https://api.github.com/repos/etalab/udata-admin/issues/events{/number}","events_url":"https://api.github.com/repos/etalab/udata-admin/events","assignees_url":"https://api.github.com/repos/etalab/udata-admin/assignees{/user}","branches_url":"https://api.github.com/repos/etalab/udata-admin/branches{/branch}","tags_url":"https://api.github.com/repos/etalab/udata-admin/tags","blobs_url":"https://api.github.com/repos/etalab/udata-admin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/etalab/udata-admin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/etalab/udata-admin/git/refs{/sha}","trees_url":"https://api.github.com/repos/etalab/udata-admin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/etalab/udata-admin/statuses/{sha}","languages_url":"https://api.github.com/repos/etalab/udata-admin/languages","stargazers_url":"https://api.github.com/repos/etalab/udata-admin/stargazers","contributors_url":"https://api.github.com/repos/etalab/udata-admin/contributors","subscribers_url":"https://api.github.com/repos/etalab/udata-admin/subscribers","subscription_url":"https://api.github.com/repos/etalab/udata-admin/subscription","commits_url":"https://api.github.com/repos/etalab/udata-admin/commits{/sha}","git_commits_url":"https://api.github.com/repos/etalab/udata-admin/git/commits{/sha}","comments_url":"https://api.github.com/repos/etalab/udata-admin/comments{/number}","issue_comment_url":"https://api.github.com/repos/etalab/udata-admin/issues/comments{/number}","contents_url":"https://api.github.com/repos/etalab/udata-admin/contents/{+path}","compare_url":"https://api.github.com/repos/etalab/udata-admin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/etalab/udata-admin/merges","archive_url":"https://api.github.com/repos/etalab/udata-admin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/etalab/udata-admin/downloads","issues_url":"https://api.github.com/repos/etalab/udata-admin/issues{/number}","pulls_url":"https://api.github.com/repos/etalab/udata-admin/pulls{/number}","milestones_url":"https://api.github.com/repos/etalab/udata-admin/milestones{/number}","notifications_url":"https://api.github.com/repos/etalab/udata-admin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/etalab/udata-admin/labels{/name}","releases_url":"https://api.github.com/repos/etalab/udata-admin/releases{/id}","created_at":"2015-03-23T09:00:31Z","updated_at":"2015-05-07T14:10:21Z","pushed_at":"2015-07-15T17:50:32Z","git_url":"git://github.com/etalab/udata-admin.git","ssh_url":"git@github.com:etalab/udata-admin.git","clone_url":"https://github.com/etalab/udata-admin.git","svn_url":"https://github.com/etalab/udata-admin","homepage":null,"size":771,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":4,"forks":1,"open_issues":4,"watchers":1,"default_branch":"master"}},"base":{"label":"etalab:master","ref":"master","sha":"92d1f0128ba240759d61a54b29471e45c5ae810b","user":{"login":"etalab","id":5313610,"avatar_url":"https://avatars.githubusercontent.com/u/5313610?v=3","gravatar_id":"","url":"https://api.github.com/users/etalab","html_url":"https://github.com/etalab","followers_url":"https://api.github.com/users/etalab/followers","following_url":"https://api.github.com/users/etalab/following{/other_user}","gists_url":"https://api.github.com/users/etalab/gists{/gist_id}","starred_url":"https://api.github.com/users/etalab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etalab/subscriptions","organizations_url":"https://api.github.com/users/etalab/orgs","repos_url":"https://api.github.com/users/etalab/repos","events_url":"https://api.github.com/users/etalab/events{/privacy}","received_events_url":"https://api.github.com/users/etalab/received_events","type":"Organization","site_admin":false},"repo":{"id":32721062,"name":"udata-admin","full_name":"etalab/udata-admin","owner":{"login":"etalab","id":5313610,"avatar_url":"https://avatars.githubusercontent.com/u/5313610?v=3","gravatar_id":"","url":"https://api.github.com/users/etalab","html_url":"https://github.com/etalab","followers_url":"https://api.github.com/users/etalab/followers","following_url":"https://api.github.com/users/etalab/following{/other_user}","gists_url":"https://api.github.com/users/etalab/gists{/gist_id}","starred_url":"https://api.github.com/users/etalab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/etalab/subscriptions","organizations_url":"https://api.github.com/users/etalab/orgs","repos_url":"https://api.github.com/users/etalab/repos","events_url":"https://api.github.com/users/etalab/events{/privacy}","received_events_url":"https://api.github.com/users/etalab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/etalab/udata-admin","description":"Admin/Backoffice for uData","fork":false,"url":"https://api.github.com/repos/etalab/udata-admin","forks_url":"https://api.github.com/repos/etalab/udata-admin/forks","keys_url":"https://api.github.com/repos/etalab/udata-admin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/etalab/udata-admin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/etalab/udata-admin/teams","hooks_url":"https://api.github.com/repos/etalab/udata-admin/hooks","issue_events_url":"https://api.github.com/repos/etalab/udata-admin/issues/events{/number}","events_url":"https://api.github.com/repos/etalab/udata-admin/events","assignees_url":"https://api.github.com/repos/etalab/udata-admin/assignees{/user}","branches_url":"https://api.github.com/repos/etalab/udata-admin/branches{/branch}","tags_url":"https://api.github.com/repos/etalab/udata-admin/tags","blobs_url":"https://api.github.com/repos/etalab/udata-admin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/etalab/udata-admin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/etalab/udata-admin/git/refs{/sha}","trees_url":"https://api.github.com/repos/etalab/udata-admin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/etalab/udata-admin/statuses/{sha}","languages_url":"https://api.github.com/repos/etalab/udata-admin/languages","stargazers_url":"https://api.github.com/repos/etalab/udata-admin/stargazers","contributors_url":"https://api.github.com/repos/etalab/udata-admin/contributors","subscribers_url":"https://api.github.com/repos/etalab/udata-admin/subscribers","subscription_url":"https://api.github.com/repos/etalab/udata-admin/subscription","commits_url":"https://api.github.com/repos/etalab/udata-admin/commits{/sha}","git_commits_url":"https://api.github.com/repos/etalab/udata-admin/git/commits{/sha}","comments_url":"https://api.github.com/repos/etalab/udata-admin/comments{/number}","issue_comment_url":"https://api.github.com/repos/etalab/udata-admin/issues/comments{/number}","contents_url":"https://api.github.com/repos/etalab/udata-admin/contents/{+path}","compare_url":"https://api.github.com/repos/etalab/udata-admin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/etalab/udata-admin/merges","archive_url":"https://api.github.com/repos/etalab/udata-admin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/etalab/udata-admin/downloads","issues_url":"https://api.github.com/repos/etalab/udata-admin/issues{/number}","pulls_url":"https://api.github.com/repos/etalab/udata-admin/pulls{/number}","milestones_url":"https://api.github.com/repos/etalab/udata-admin/milestones{/number}","notifications_url":"https://api.github.com/repos/etalab/udata-admin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/etalab/udata-admin/labels{/name}","releases_url":"https://api.github.com/repos/etalab/udata-admin/releases{/id}","created_at":"2015-03-23T09:00:31Z","updated_at":"2015-05-07T14:10:21Z","pushed_at":"2015-07-15T17:50:32Z","git_url":"git://github.com/etalab/udata-admin.git","ssh_url":"git@github.com:etalab/udata-admin.git","clone_url":"https://github.com/etalab/udata-admin.git","svn_url":"https://github.com/etalab/udata-admin","homepage":null,"size":771,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":4,"forks":1,"open_issues":4,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/etalab/udata-admin/pulls/25"},"html":{"href":"https://github.com/etalab/udata-admin/pull/25"},"issue":{"href":"https://api.github.com/repos/etalab/udata-admin/issues/25"},"comments":{"href":"https://api.github.com/repos/etalab/udata-admin/issues/25/comments"},"review_comments":{"href":"https://api.github.com/repos/etalab/udata-admin/pulls/25/comments"},"review_comment":{"href":"https://api.github.com/repos/etalab/udata-admin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/etalab/udata-admin/pulls/25/commits"},"statuses":{"href":"https://api.github.com/repos/etalab/udata-admin/statuses/d1b0569cdeef890ba81180397e8079f01cc19220"}}}}