Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| /** | |
| * Bookie's View objects used to represent pages or parts of page content. | |
| * | |
| * @namespace bookie | |
| * @module view | |
| * | |
| */ | |
| YUI.add('bookie-view', function (Y) { | |
| var _ = Y.substitute, | |
| ns = Y.namespace('bookie'); | |
| /** | |
| * Display a list of bookmarks from the API to the end user. | |
| * | |
| * @class BmarkListView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.BmarkListView = Y.Base.create('bookie-list-view', Y.View, [], { | |
| container_html: '<div class="bmark_list"/>', | |
| /** | |
| * @method _get_template | |
| * @private | |
| * | |
| */ | |
| _get_template: function () { | |
| return Y.one('#bmark_list').get('text'); | |
| }, | |
| events: {}, | |
| /** | |
| * Prepare and add the pager view for our control | |
| * | |
| * We need two, one for the top and one for the bottom | |
| * | |
| * @method _init_pager | |
| * @private | |
| * | |
| */ | |
| _init_pager: function () { | |
| var that = this; | |
| that.pagers = [ | |
| new Y.bookie.PagerView(), | |
| new Y.bookie.PagerView() | |
| ]; | |
| that.set('pager', new Y.bookie.PagerModel()); | |
| // If the pager is ever updated, make sure we watch it for changes | |
| // again. | |
| that.after('pagerChange', function (ev) { | |
| // Setup an event to watch out pagerModel. | |
| // Now that we've incremented the page let's fetch a new set of | |
| // results. | |
| that.get('pager').after('pageChange', function (ev) { | |
| if (ev.newVal !== ev.prevVal) { | |
| that._fetch_dataset(); | |
| } | |
| }, that); | |
| }, this); | |
| // bind the pager event | |
| Y.on('pager:next', that._next_page, that); | |
| Y.on('pager:previous', that._prev_page, that); | |
| }, | |
| /** | |
| * Setup the api call for filling in our data based on our config | |
| * | |
| * @method _init_api | |
| * @private | |
| * | |
| */ | |
| _init_api: function () { | |
| var api_callable = this.get('api_callable'); | |
| this.api = new api_callable(this.get('api_cfg')); | |
| }, | |
| /** | |
| * | |
| * @method _init_indicator | |
| * @private | |
| * | |
| */ | |
| _init_indicator: function () { | |
| this.indicator = new Y.bookie.Indicator({ | |
| target: Y.one('.bmarks') | |
| }); | |
| this.indicator.render(); | |
| }, | |
| /** | |
| * Fetch a dataset based on our current data | |
| * | |
| * @method _fetch_dataset | |
| * @private | |
| * | |
| */ | |
| _fetch_dataset: function () { | |
| var that = this, | |
| pager = this.get('pager'); | |
| // make sure we update the api paging information with the latest | |
| // from our pager | |
| this.indicator.show(); | |
| this.api.data.count = pager.get('count'); | |
| this.api.data.page = pager.get('page'); | |
| this.api.call({ | |
| 'success': function (data, request) { | |
| var data_node = Y.one('.data_list'), | |
| new_nodes = new Y.NodeList(); | |
| if (data.count === 0) { | |
| // If there is not filter in place then this is a new | |
| if(!data.tag_filter || data.tag_filter.length === 0) { | |
| // user showing their 'recent' bookmarks. | |
| that.models = []; | |
| var tpl = Y.one('#new_user').get('text'), | |
| welcome = Y.Handlebars.compile(tpl); | |
| data_node.setContent(welcome({ | |
| username: that.get('resource_user') | |
| })); | |
| } else { | |
| // If there is a filter in place, then there's | |
| // just no results for this call. Let the user | |
| // know there's nadda here. | |
| var no_results = Y.Node.create( | |
| '<h3 class="heading"></h3>'); | |
| data_node.setContent( | |
| no_results.setContent( | |
| 'No results found for specified search.') | |
| ); | |
| } | |
| } else { | |
| // build models out of our data | |
| that.models = Y.Array.map(data[that.get('results_key')], | |
| function (bmark) { | |
| bmark.api_cfg = that.get('api_cfg'); | |
| var b = new Y.bookie.Bmark(bmark), | |
| n = new Y.bookie.BmarkView({ | |
| model: b, | |
| current_user: that.get('current_user'), | |
| resource_user: that.get('resource_user') | |
| } | |
| ); | |
| b.api_cfg = that.get('api_cfg'); | |
| new_nodes.push(n.render()); | |
| return b; | |
| } | |
| ); | |
| // now set the html | |
| data_node.setContent(new_nodes); | |
| } | |
| // update the pagers | |
| that._update_pagerview(); | |
| // finally stop the indicator from spinny spinny | |
| that.indicator.hide(); | |
| } | |
| }); | |
| }, | |
| /** | |
| * Increment the pager and fetch the next results from the last call. | |
| * | |
| * @method _next_page | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _next_page: function (e) { | |
| var pager = this.get('pager'); | |
| pager.next(); | |
| }, | |
| /** | |
| * Update the html reprensenting our Pager information after loading a | |
| * dataset. For instance, should we hide the prev control if we're | |
| * onthe first page of results? If we're on last page should we be | |
| * hiding the next control? | |
| * | |
| * @method _update_pagerview | |
| * @private | |
| * | |
| */ | |
| _update_pagerview: function () { | |
| var pager = this.get('pager'); | |
| // if the current data count is < the pager page count, hide next | |
| if (this.models && (this.models.length < pager.get('count'))) { | |
| Y.Array.each(this.pagers, function (p) { | |
| p.set('show_next', false); | |
| }); | |
| } else { | |
| Y.Array.each(this.pagers, function (p) { | |
| p.set('show_next', true); | |
| }); | |
| } | |
| // update the pagers | |
| if (pager.get('page') === 0) { | |
| // then there is no need for a previous button | |
| Y.Array.each(this.pagers, function (p) { | |
| p.set('show_previous', false); | |
| }); | |
| } else { | |
| Y.Array.each(this.pagers, function (p) { | |
| p.set('show_previous', true); | |
| }); | |
| } | |
| // @todo get rid of this. Changing the showXXX value should fire | |
| // an event that causes the pagers to re-render themselves, not us | |
| // manually | |
| Y.Array.each(this.pagers, function (p) { | |
| p.render(); | |
| }); | |
| }, | |
| /** | |
| * Decrement the pager for the current list and fetch a new set of | |
| * results. | |
| * | |
| * @method _prev_page | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _prev_page: function (e) { | |
| var pager = this.get('pager'); | |
| pager.previous(); | |
| }, | |
| /** | |
| * Initializer for a class extending Y.Base | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * @constructor | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this.cTemplate = Y.Handlebars.compile(this._get_template()); | |
| this._init_pager(); | |
| this._init_api(); | |
| this._init_indicator(); | |
| }, | |
| /** | |
| * Build the UI for the result set we've gotten from the API. | |
| * | |
| * @method render | |
| * | |
| */ | |
| render: function () { | |
| var that = this, | |
| pager_html, | |
| idx = 0, | |
| // Render this view's HTML into the container element. | |
| html = this.get('container').set( | |
| 'innerHTML', | |
| this.cTemplate(this.getAttrs()) | |
| ); | |
| // start the request for our models | |
| this._fetch_dataset(); | |
| pager_html = html.all('.paging'); | |
| pager_html.each(function (n) { | |
| var p = that.pagers[idx]; | |
| n.appendChild(p.render()); | |
| idx = idx + 1; | |
| }); | |
| // Watch the API event to make sure we update the rss link. | |
| that.rss = new Y.bookie.rsswatch.Updater(); | |
| Y.on('api:loaded', function (ev) { | |
| if (ev.url.indexOf('api/v1/bmarks') !== -1) { | |
| that.rss.fire('update', { | |
| data_url: ev.url | |
| }); | |
| } | |
| }); | |
| return html; | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * We're creating a new set of html for our results by getting the | |
| * container_html. | |
| * | |
| * @attribute container | |
| * @type Y.Node | |
| * | |
| */ | |
| container: { | |
| valueFn: function() { | |
| return Y.Node.create(this.container_html); | |
| } | |
| }, | |
| /** | |
| * You need to override this in extending classes that tells the | |
| * view how to fetch results to put into this view when things | |
| * like pagers and such change | |
| * | |
| * @attribute api_callable | |
| * @default Api.route.UserBmarksAll | |
| * @readonly | |
| * | |
| */ | |
| api_callable: { | |
| readonly: true, | |
| getter: function () { | |
| return Y.bookie.Api.route.UserBmarksAll; | |
| } | |
| }, | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| }, | |
| /** | |
| * You can add a filter control into the bmark list view. This | |
| * method is over rideable so that you can figure out how to fetch | |
| * the filters to apply to the api calls. | |
| * | |
| * @attribute filter_control | |
| * @default '' | |
| * | |
| */ | |
| filter_control: { | |
| value: '' | |
| }, | |
| /** | |
| * @attribute pager | |
| * @default new PagerModel | |
| * @type PagerModel | |
| * | |
| */ | |
| pager: { | |
| valueFn: function () { | |
| return new Y.bookie.PagerModel(); | |
| } | |
| }, | |
| /** | |
| * Who is the currently auth'd user | |
| * | |
| * @attribute current_user | |
| * @default undefined | |
| * @type String | |
| * | |
| */ | |
| current_user: { | |
| }, | |
| /** | |
| * What is the user that owns this collection | |
| * | |
| * e.g. /admin/bmarks == admin user even though I'm not logged in | |
| * as admin | |
| * | |
| * @attribute resource_user | |
| * @default undefined | |
| * @type String | |
| */ | |
| resource_user: { | |
| }, | |
| /** | |
| * Where in the results can we find out bmarks? | |
| * | |
| * @attribute results_key | |
| * @readonly | |
| * @default 'bmarks' | |
| * @type String | |
| * | |
| */ | |
| results_key: { | |
| value: 'bmarks', | |
| readonly: true | |
| } | |
| } | |
| }); | |
| /** | |
| * Extends BmarkListView to specify a view used for the main /recent pages | |
| * for displaying lists of bookmarks with a tag control widget tied into | |
| * the game. | |
| * | |
| * @class TagControlBmarkListView | |
| * @extends BmarkListView | |
| * | |
| */ | |
| ns.TagControlBmarkListView = Y.Base.create('tagcontrol-bookie-list-view', ns.BmarkListView, [], { | |
| /** | |
| * Standard initializer, note that this ends up being "appended" not | |
| * replacing the parent's initializer method. | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| // if there are tags added/removed form the TagControl, then make | |
| // sure we update the list accordingly | |
| Y.on('tag:changed', this._tags_changed, this); | |
| }, | |
| /** | |
| * Handle when tags in the control are changed. | |
| * | |
| * @method _tags_changed | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _tags_changed: function (e) { | |
| var api_tags = this.api.get('tags'); | |
| if (!api_tags) { | |
| api_tags = []; | |
| } | |
| // Only update if the tags have changed. This is hacky as can be | |
| // because comparing two JS arrays will fail unless you loop | |
| // through them. This is a cheat and might fail if the end of one | |
| // tag combines with the start of another tag, but I think this is | |
| // a good start. | |
| if (e.tags.join('') != api_tags.join('')) { | |
| // update the api data with the tags list | |
| this.api.set('tags', e.tags); | |
| // update the pager back to page 1 | |
| this.get('pager').set('page', 0); | |
| // and finally fetch the results | |
| this._fetch_dataset(); | |
| } | |
| } | |
| }, { | |
| ATTRS: { | |
| api_callable: { | |
| readonly: true, | |
| // then there's a user in our resource path, make the api call a | |
| // UserBmarksAll vs BmarksAll | |
| getter: function () { | |
| if (this.get('resource_user')) { | |
| var cfg = this.get('api_cfg'); | |
| cfg.resource = this.get('resource_user'); | |
| this.set('api_cfg', cfg); | |
| return Y.bookie.Api.route.UserBmarksAll; | |
| } else { | |
| return Y.bookie.Api.route.BmarksAll; | |
| } | |
| } | |
| }, | |
| filter_control: { | |
| getter: function () { | |
| return Y.Handlebars.compile( | |
| Y.one('#filter_container').get('text') | |
| )({}); | |
| } | |
| } | |
| } | |
| }); | |
| /** | |
| * Extends BmarkListView to specify a view used for the main /search pages | |
| * for displaying lists of bookmarks from a search result for the user. | |
| * | |
| * @class SearchControlBmarkListView | |
| * @extends BmarkListView | |
| * | |
| */ | |
| ns.SearchingBmarkListView = Y.Base.create('tagcontrol-bookie-list-view', ns.TagControlBmarkListView, [], { | |
| /** | |
| * Handle when tags in the control are changed. | |
| * | |
| * @method _tags_changed | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _tags_changed: function (e) { | |
| // update the api data with the tags list | |
| this.api.set('phrase', e.tags); | |
| // update the pager back to page 1 | |
| this.get('pager').set('page', 0); | |
| // and finally fetch the results | |
| this._fetch_dataset(); | |
| } | |
| }, { | |
| ATTRS: { | |
| api_callable: { | |
| readonly: true, | |
| // then there's a user in our resource path, make the api call a | |
| // UserBmarksAll vs BmarksAll | |
| getter: function () { | |
| if (this.get('resource_user')) { | |
| return Y.bookie.Api.route.UserSearch; | |
| } else { | |
| return Y.bookie.Api.route.Search; | |
| } | |
| } | |
| }, | |
| /** | |
| * The list of phrase bits to search on split on list. | |
| * | |
| * @attribute phrase | |
| * @default [] | |
| * @type Array | |
| * | |
| */ | |
| phrase: { | |
| value: [] | |
| }, | |
| /** | |
| * Where in the results can we find out bmarks? | |
| * | |
| * @attribute results_key | |
| * @readonly | |
| * @default 'search_results' | |
| * @type String | |
| * | |
| */ | |
| results_key: { | |
| value: 'search_results', | |
| readonly: true | |
| } | |
| } | |
| }); | |
| /** | |
| * A View for handling representing our paging controls for next/prev | |
| * pages. | |
| * | |
| * @class PagerView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.PagerView = Y.Base.create('bookie-pager-view', Y.View, [], { | |
| container_html: '<div class="pager"/>', | |
| /** | |
| * Fetch the templates used from the script tags in the html. | |
| * | |
| * @method _get_templates | |
| * @private | |
| * | |
| */ | |
| _get_templates: function () { | |
| return { | |
| prev: Y.one('#previous_control').get('text'), | |
| next: Y.one('#next_control').get('text') | |
| }; | |
| }, | |
| /** | |
| * Make sure the previous contol is visible to the user. | |
| * | |
| * @method _show_previous | |
| * @param {Event} e | |
| * | |
| */ | |
| _show_previous: function (e) { | |
| var val = e.newVal, | |
| prev = e.prevVal; | |
| // make sure we update render | |
| // but only if the value is different | |
| if (val && val !== prev) { | |
| this.render(); | |
| } | |
| }, | |
| /** | |
| * Make sure that we display the next control properly. | |
| * | |
| * @method _show_next | |
| * @param {Event} e | |
| * | |
| */ | |
| _show_next: function (e) { | |
| var val = e.newVal, | |
| prev = e.prevVal; | |
| // make sure we update render | |
| // but only if the value is different | |
| if (val && val !== prev) { | |
| this.render(); | |
| } | |
| }, | |
| /** | |
| * @attribute events | |
| * @default Object | |
| * | |
| */ | |
| events: { | |
| '.previous': { | |
| click: 'previous_page' | |
| }, | |
| '.next': { | |
| click: 'next_page' | |
| } | |
| }, | |
| /** | |
| * Basic initializer | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * @event show_previousChange | |
| * @event show_nextChange | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| var tpl = this._get_templates(); | |
| this.cPrevTemplate = Y.Handlebars.compile(tpl.prev); | |
| this.cNextTemplate = Y.Handlebars.compile(tpl.next); | |
| this.after('show_previousChange', this._show_previous, this); | |
| this.after('show_nextChange', this._show_next, this); | |
| }, | |
| /** | |
| * Handle the previous page clicked event. | |
| * | |
| * @method previous_page | |
| * @param {Event} e | |
| * | |
| */ | |
| previous_page: function (e) { | |
| e.preventDefault(); | |
| Y.fire(this.get('previous_event')); | |
| }, | |
| /** | |
| * Handle the next page clicked event. | |
| * | |
| * @method next_page | |
| * @param {Event} e | |
| * | |
| */ | |
| next_page: function (e) { | |
| e.preventDefault(); | |
| Y.fire(this.get('next_event')); | |
| }, | |
| /** | |
| * render out the control to the container specified. | |
| * | |
| * @method render | |
| * @return {String} generated html | |
| * | |
| */ | |
| render: function () { | |
| // Render this view's HTML into the container element. | |
| return this.get('container').set( | |
| 'innerHTML', | |
| this.cPrevTemplate(this.getAttrs()) + | |
| this.cNextTemplate(this.getAttrs()) | |
| ); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute container | |
| * @default Y.Node | |
| * @type Y.Node | |
| * | |
| */ | |
| container: { | |
| valueFn: function () { | |
| return Y.Node.create(this.container_html); | |
| } | |
| }, | |
| /** | |
| * @attribute id | |
| * @default 'pager' | |
| * @type String | |
| * | |
| */ | |
| id: { | |
| value: 'pager' | |
| }, | |
| /** | |
| * @attribute previous_event | |
| * @default '$id:previous' | |
| * @type String | |
| * @readonly | |
| * | |
| */ | |
| previous_event: { | |
| readOnly: true, | |
| valueFn: function () { | |
| return this.get('id') + ':previous'; | |
| } | |
| }, | |
| /** | |
| * @attribute next_event | |
| * @default '$id:next' | |
| * @type String | |
| * @readonly | |
| * | |
| */ | |
| next_event: { | |
| readOnly: true, | |
| valueFn: function () { | |
| return this.get('id') + ':next'; | |
| } | |
| }, | |
| /** | |
| * By default we don't need a previous usually on initial page | |
| * load | |
| * | |
| * @attribute show_previous | |
| * @default false | |
| * @type Boolean | |
| * | |
| */ | |
| show_previous: { | |
| value: false | |
| }, | |
| /** | |
| * @attribute show_next | |
| * @default true | |
| * @type Boolean | |
| * | |
| */ | |
| show_next: { | |
| value: true | |
| } | |
| } | |
| }); | |
| /** | |
| * This is the view for a single bookmark in a result set. It handles its | |
| * own events and rendering/updating and this is where the remove event | |
| * from the UI gets captured and passed along to the bound model. | |
| * | |
| * @class BmarkView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.BmarkView = Y.Base.create('bookie-bmark-view', Y.View, [], { | |
| container_html: '<div class="bmark"/>', | |
| /** | |
| * Get the template string used to render this view. | |
| * | |
| * @method _get_template | |
| * @private | |
| * | |
| */ | |
| _get_template: function () { | |
| return Y.one('#bmark_row').get('text'); | |
| }, | |
| /** | |
| * If you click on a tag in the bookmark view filter the page to just | |
| * that tag. | |
| * | |
| * @method _tag_filter | |
| * @private | |
| * | |
| */ | |
| _tag_filter: function (e) { | |
| e.preventDefault(); | |
| // find the tag we need to pass in the event | |
| Y.fire('tag:add', {tag: e.currentTarget.get('text')}); | |
| }, | |
| events: { | |
| '.delete': { | |
| click: 'remove' | |
| }, | |
| '.tag': { | |
| click: '_tag_filter' | |
| } | |
| }, | |
| /** | |
| * General initializer method. | |
| * | |
| * @method intializer | |
| * @param {Object} cfg | |
| * @constructor | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this.cTemplate = Y.Handlebars.compile(this._get_template()); | |
| }, | |
| /** | |
| * Handle the remove event on this bookmark | |
| * | |
| * @method remove | |
| * | |
| */ | |
| remove: function (ev) { | |
| ev.halt(); | |
| var that = this; | |
| this.get('model').remove(); | |
| this.get('container').transition({ | |
| easing: 'ease', | |
| duration: 0.4, | |
| opacity: 0 | |
| }, function () { | |
| that.destroy({ | |
| // we need to pass remove so that the node is actually | |
| // removed during the destroy process | |
| remove: true | |
| }); | |
| }); | |
| }, | |
| /** | |
| * Render out html for this bookmark based on the model data. | |
| * | |
| * @method render | |
| * @return Y.Node | |
| * | |
| */ | |
| render: function () { | |
| // Render this view's HTML into the container element. | |
| var tpl_data = this.get('model').getAttrs(); | |
| tpl_data.owner = this.get('current_user') === this.get('model').get('username'); | |
| return this.get('container').set( | |
| 'innerHTML', | |
| this.cTemplate(tpl_data) | |
| ); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * | |
| * The view is for a url of a specific user. | |
| * | |
| * Say /admin/bmarks for the admin bookmarks, does not mean I'm | |
| * the admin. | |
| * | |
| * @attribute resource_user | |
| * @default undefined | |
| * @type String | |
| * | |
| */ | |
| resource_user: { | |
| }, | |
| /** | |
| * The current authorized user. | |
| * | |
| * @attribute current_user | |
| * @default undefined | |
| * @type String | |
| * | |
| */ | |
| current_user: { | |
| }, | |
| /** | |
| * Each view is rendered into a container node that's then | |
| * returned via the render method. | |
| * | |
| * @attribute container | |
| * @default Y.Node | |
| * @type Y.Node | |
| * @readonly | |
| * | |
| */ | |
| container: { | |
| valueFn: function () { | |
| var container = Y.Node.create(this.container_html); | |
| container.setAttribute( | |
| 'data-bid', | |
| this.get('model').get('bid') | |
| ); | |
| return container; | |
| } | |
| } | |
| } | |
| }); | |
| /** | |
| * Adding Javascript help for Bookmark Edit | |
| * | |
| * @class BmarkEditView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.BmarkEditView = Y.Base.create('bmark-edit-view', Y.View, [], { | |
| /** | |
| * Checks if header is persent for the url if not add http:// to | |
| * the url | |
| * | |
| * @method _check_and_edit_url | |
| * @param {Event} e | |
| * | |
| */ | |
| _check_and_edit_url: function (e) { | |
| var str = e.target.get('value'); | |
| if(!(/^(f|ht)tps?:\/\//.test(str))){ | |
| str = "http://" + str; | |
| } | |
| e.target.set('value', str); | |
| }, | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param none | |
| * | |
| */ | |
| initializer: function () { | |
| // The url is not editable. So if we don't have the input, assume | |
| // it's an edit and skip. | |
| var url_input = Y.one('input#url'); | |
| if (url_input) { | |
| url_input.on('blur', this._check_and_edit_url); | |
| } | |
| } | |
| }); | |
| /** | |
| * Generate the view for user stats | |
| * @class UserStatsView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.UserStatsView = Y.Base.create('user-stats-view', Y.View, [], { | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param none | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this.api = new Y.bookie.Api.route.UserStats(cfg.api_cfg); | |
| }, | |
| render: function () { | |
| var that = this; | |
| this.api.call({ | |
| success: function(data, request) { | |
| var cont = that.get('container'); | |
| cont.one('#user_stats_count').setContent( | |
| data.count); | |
| cont.one('#user_stats_activations').setContent( | |
| data.activations); | |
| cont.one('#user_stats_with_bookmarks').setContent( | |
| data.with_bookmarks); | |
| cont.one('#user_stats_msg').setContent(''); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| var cont = that.get('container'); | |
| cont.one('#user_stats_msg').setContent( | |
| 'Error fetching stats'); | |
| } | |
| }); | |
| } | |
| }); | |
| /** | |
| * Generate the view for bookmark stats | |
| * | |
| * @class BookmarkStatsView | |
| * extends Y.View | |
| * | |
| */ | |
| ns.BookmarkStatsView = Y.Base.create('bookmark-stats-view', Y.View, [], { | |
| /** | |
| * | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param none | |
| * | |
| */ | |
| initializer: function(cfg) { | |
| this.api = new Y.bookie.Api.route.BookmarkStats(cfg.api_cfg); | |
| }, | |
| render: function () { | |
| var that = this; | |
| this.api.call({ | |
| success: function(data, request) { | |
| var cont = that.get('container'); | |
| cont.one('#bookmark_stats_count').setContent( | |
| data.count); | |
| cont.one('#bookmark_stats_unique_count').setContent( | |
| data.unique_count); | |
| cont.one('#bookmark_stats_fulltext_count').setContent( | |
| data.in_fulltext); | |
| cont.one('#bookmark_stats_msg').setContent(''); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| var cont = that.get('container'); | |
| cont.one('#bookmark_stats_msg').setContent('Error fetching stats'); | |
| } | |
| }); | |
| } | |
| }); | |
| /** | |
| * Generate the graph for user bookmark count | |
| * | |
| * @class UserBmarkCountView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.UserBmarkCountView = Y.Base.create('user-bmark-count-view', Y.View, [], { | |
| /** | |
| * Handles the start and end dates when dates are changed. | |
| * | |
| * @method _date_range | |
| * @private | |
| * | |
| */ | |
| _date_range: function(e) { | |
| var dtdate = Y.DataType.Date; | |
| var start_date = e.newSelection[0]; | |
| var end_date = e.newSelection[1]; | |
| if (start_date && end_date && (end_date < start_date)) { | |
| var temp_date = start_date; | |
| start_date = dtdate.format(end_date); | |
| end_date = dtdate.format(temp_date); | |
| } | |
| else { | |
| start_date = dtdate.format(start_date); | |
| end_date = dtdate.format(end_date); | |
| } | |
| this.api_cfg = Y.merge(this.api_cfg, { | |
| start_date: start_date, | |
| end_date: end_date, | |
| }); | |
| this._fetch_dataset(); | |
| }, | |
| /** | |
| * Handles the json response after the api call | |
| * | |
| * @method _fetch_dataset | |
| * @private | |
| * | |
| */ | |
| _fetch_dataset: function(data) { | |
| var that = this; | |
| this.api = new Y.bookie.Api.route.UserBmarkCount(this.api_cfg); | |
| this.api.call({ | |
| success: function(data, request) { | |
| Y.one('#userstats_msg').setContent(''); | |
| Y.one('#userstats_msg').hide(); | |
| // Stores the data for the graph. | |
| var myDataValues = []; | |
| data.count.forEach(function(value) { | |
| myDataValues.push({ | |
| date: value.tstamp.split(' ')[0], | |
| bookmarks: value.data | |
| }); | |
| }); | |
| var user_graph = Y.one('#bmark_count_graph'); | |
| user_graph.setContent(); | |
| var graph_render = new Y.Chart({ | |
| dataProvider: myDataValues, | |
| axes: that.myAxes, | |
| seriesCollection: that.seriesCollection, | |
| render: user_graph | |
| }); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| Y.one('#userstats_msg').show(); | |
| Y.one('#userstats_msg').setContent('Error fetching the bookmark count'); | |
| } | |
| }); | |
| }, | |
| /** | |
| * Renders the calendar to the html view. | |
| * | |
| * @method _set_calendar | |
| * @private | |
| * | |
| */ | |
| _set_calendar: function() { | |
| Y.CalendarBase.CONTENT_TEMPLATE = Y.CalendarBase.TWO_PANE_TEMPLATE; | |
| this.calendar = new Y.Calendar({ | |
| contentBox: "#calendar", | |
| selectionMode: "multiple", | |
| showPrevMonth: true, | |
| showNextMonth: true, | |
| date: new Date()}).render(); | |
| this.calendar.on('selectionChange', | |
| this._date_range, | |
| this | |
| ); | |
| this.calendar.set("headerRenderer", function (curDate) { | |
| var ydate = Y.DataType.Date, | |
| output = ydate.format(curDate, { | |
| format: "%B %Y" | |
| }) + " — " + ydate.format(ydate.addMonths(curDate, 1), { | |
| format: "%B %Y" | |
| }); | |
| return output; | |
| }); | |
| }, | |
| /** | |
| * Sets the graph properties | |
| * | |
| * @method _graph_properties | |
| * @private | |
| * | |
| */ | |
| _graph_properties: function() { | |
| this.myAxes = { | |
| bookmarks:{ | |
| keys:["bookmarks"], | |
| position:"left", | |
| type:"numeric", | |
| minimum: 0, | |
| styles:{ | |
| majorTicks:{ | |
| display: "none" | |
| } | |
| } | |
| }, | |
| dateRange:{ | |
| keys:["date"], | |
| position:"bottom", | |
| type:"category", | |
| styles:{ | |
| majorTicks:{ | |
| display: "none" | |
| }, | |
| label: { | |
| rotation:-45, | |
| margin:{top:5} | |
| } | |
| } | |
| } | |
| }; | |
| this.seriesCollection = [ | |
| { | |
| xAxis: "dateRange", | |
| yAxis: "bookmarks", | |
| xKey: "date", | |
| yKey: "bookmarks", | |
| xDisplayName: "Date", | |
| yDisplayName: "Bookmarks" | |
| } | |
| ]; | |
| }, | |
| initializer: function (cfg) { | |
| this.api_cfg = this.get('api_cfg'); | |
| this._graph_properties(); | |
| this.get('container'); | |
| }, | |
| /** | |
| * Build the UI for the result set we have | |
| * | |
| * @method render | |
| * | |
| */ | |
| render: function() { | |
| this._set_calendar(); | |
| this._fetch_dataset(); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| required: true | |
| } | |
| } | |
| }); | |
| /** | |
| * Generate the html view for a User's account | |
| * | |
| * @class AccountView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.AccountView = Y.Base.create('bookie-account-view', Y.View, [], { | |
| _blet_visible: false, | |
| _api_visible: false, | |
| /** | |
| * Bind all events for this html view. | |
| * | |
| * @method _bind | |
| * | |
| */ | |
| _bind: function () { | |
| Y.one('#show_key').on( | |
| 'click', | |
| this._show_api_key, | |
| this | |
| ); | |
| Y.one('#show_bookmarklet').on( | |
| 'click', | |
| this._show_bookmarklet, | |
| this | |
| ); | |
| Y.one('#new_api_key').on( | |
| 'click', | |
| this._new_api_key, | |
| this | |
| ); | |
| }, | |
| /** | |
| * Handle displaying the API key for a user. This requires making an | |
| * API request since we don't dump the API key by default into the | |
| * page html to help prevent it leaking out. | |
| * | |
| * @method _show_api_key | |
| * @param {Event} e | |
| * | |
| */ | |
| _show_api_key: function (e) { | |
| var key_div = Y.one('#api_key'), | |
| key_container = Y.one('#api_key_container'), | |
| api; | |
| e.preventDefault(); | |
| // if the api key is showing and they click this, hide it | |
| if(this._api_visible) { | |
| key_container.hide(true); | |
| this._api_visible = false; | |
| } else { | |
| api = new Y.bookie.Api.route.UserApiKey(this.get('api_cfg')); | |
| this._api_visible = true; | |
| // make an ajax request to get the api key for this user and then | |
| // show it in the container for it | |
| api.call({ | |
| success: function (data, request) { | |
| key_div.setContent(data.api_key); | |
| key_container.show(true); | |
| } | |
| }); | |
| } | |
| }, | |
| /** | |
| * Handle displaying the bookmarklet information when the user | |
| * requests it. | |
| * | |
| * @method _show_bookmarklet | |
| * @param {Event} e | |
| * | |
| */ | |
| _show_bookmarklet: function (e) { | |
| var blet = Y.one('#bookmarklet_text'); | |
| e.preventDefault(); | |
| // if the api key is showing and they click this, hide it | |
| // the opacity must start out at 0 for the transition to take | |
| // effect | |
| if(this._blet_visible) { | |
| this._blet_visible = false; | |
| blet.hide(true); | |
| } else { | |
| this._blet_visible = true; | |
| blet.show(true); | |
| } | |
| }, | |
| /** | |
| * Handle new API key request. | |
| * | |
| * @method _new_api_key | |
| * @param {Event} e | |
| * | |
| */ | |
| _new_api_key: function(e) { | |
| e.preventDefault(); | |
| var that = this; | |
| this._show_message('', false); | |
| // Safety check. | |
| if (this._api_visible) { | |
| var keyHandle = Y.one('#api_key'), | |
| oldKey = keyHandle.get('text'); | |
| var cfg = this.get('api_cfg'); | |
| var api = new Y.bookie.Api.route.NewApiKey(cfg); | |
| keyHandle.setContent('Requesting a new key...'); | |
| // Send a POST request to the Bookie server. | |
| api.call({ | |
| success: function(data, request) { | |
| var msg = ""; | |
| // Make sure we don't run into errors. | |
| if (!data || !data.api_key) { | |
| msg = 'Unexpected response from server'; | |
| that._show_message(msg, false); | |
| keyHandle.setContent(oldKey); | |
| return; | |
| } | |
| // Unable to reset API key due to some reason. | |
| if (data.api_key === oldKey) { | |
| msg = 'Could not generate new API key.'; | |
| msg += 'Please try later.'; | |
| that._show_message(msg, false); | |
| keyHandle.setContent(oldKey); | |
| return; | |
| } | |
| // Update the Account View instance so that | |
| // subsequent requests originating from this | |
| // instance use the new API key that is generated. | |
| var cfg = that.get('api_cfg'); | |
| cfg.api_key = data.api_key; | |
| that.set('api_cfg', cfg); | |
| if (data.message) { | |
| that._show_message(data.message, true); | |
| } | |
| keyHandle.setContent(data.api_key); | |
| } | |
| }); | |
| } else { | |
| return; | |
| } | |
| }, | |
| /** | |
| * Keep the user updated about the current process. | |
| * | |
| * @method _show_message | |
| * @param {String} msg | |
| * @param {Boolean} success | |
| * | |
| */ | |
| _show_message: function(msg, success) { | |
| var msg_div = Y.one('#new_key_msg'); | |
| msg_div.setContent(msg); | |
| if (success) { | |
| msg_div.replaceClass('error', 'success'); | |
| } else { | |
| msg_div.replaceClass('success', 'error'); | |
| } | |
| msg_div.show(true); | |
| }, | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this._bind(); | |
| // setup the password view | |
| // it needs the api cfg for updating the password via the api | |
| this.password = new ns.PasswordView({ | |
| api_cfg: this.get('api_cfg') | |
| }); | |
| this.account_info = new ns.AccountInfoView({ | |
| api_cfg: this.get('api_cfg') | |
| }); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| required: true | |
| } | |
| } | |
| }); | |
| /** | |
| * Generate the html view for a User's invite setup. | |
| * | |
| * @class InviteView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.InviteView = Y.Base.create('bookie-invite-view', Y.View, [], { | |
| _visible: false, | |
| _get_template: function () { | |
| return Y.one('#account_invites').get('text'); | |
| }, | |
| events: { | |
| 'input#send_invite': { | |
| click: 'invite' | |
| }, | |
| 'form': { | |
| submit: 'kill' | |
| }, | |
| '.heading': { | |
| click: '_toggle_container' | |
| } | |
| }, | |
| _resetui: function (success) { | |
| var email = Y.one('#invite_email').set('value', ''); | |
| if (success) { | |
| // decrement the UI counter so they appear to have fewer invites | |
| // get the current value | |
| var cont = Y.one('.invite_count'), | |
| ct = parseInt(cont.get('text'), 10); | |
| cont.set('text', (ct - 1)); | |
| } | |
| this.ind.hide(); | |
| }, | |
| /** | |
| * Handle displaying the API key for a user. This requires making an | |
| * API request since we don't dump the API key by default into the | |
| * page html to help prevent it leaking out. | |
| * | |
| * @method _show_api_key | |
| * @param {Event} e | |
| * | |
| */ | |
| _toggle_container: function (ev) { | |
| var body = this.get('container').one('#invite_body'); | |
| ev.preventDefault(); | |
| // if the api key is showing and they click this, hide it | |
| if(this._visible) { | |
| body.hide(true); | |
| this._visible = false; | |
| } else { | |
| body.show(true); | |
| this._visible = true; | |
| } | |
| }, | |
| kill: function (ev) { | |
| // make sure we don't fire the form submit | |
| ev.preventDefault(); | |
| }, | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this.ctpl = Y.Handlebars.compile(this._get_template()); | |
| }, | |
| invite: function (ev) { | |
| ev.preventDefault(); | |
| // we should be handling the api call here | |
| var that = this, | |
| email = Y.one('#invite_email').get('value'), | |
| api_cfg = this.get('api_cfg'); | |
| this.ind = new Y.bookie.Indicator({ | |
| target: this.get('container') | |
| }); | |
| this.ind.render(); | |
| this.ind.show(); | |
| api_cfg.email = email; | |
| api = new Y.bookie.Api.route.Invite(api_cfg); | |
| api.call({ | |
| success: function (data, request) { | |
| that._show_message(data.message, true); | |
| that._resetui(true); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| that._show_message(data.error, false); | |
| that._resetui(false); | |
| } | |
| }); | |
| }, | |
| render: function () { | |
| this.get('container').setContent(this.ctpl(this.get('user'))); | |
| }, | |
| /** | |
| * Display any message based on if the invite is successful or ended | |
| * in error. | |
| * | |
| * @method _show_message | |
| * @param {String} msg | |
| * @param {Boolean} success | |
| * | |
| */ | |
| _show_message: function (msg, success) { | |
| var msg_div = Y.one('#invite_msg'); | |
| msg_div.setContent(msg); | |
| if (success) { | |
| msg_div.replaceClass('error', 'success'); | |
| } else { | |
| msg_div.replaceClass('success', 'error'); | |
| } | |
| msg_div.show(true); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| required: true | |
| }, | |
| container: { | |
| valueFn: function () { | |
| return Y.one('#invite_container'); | |
| } | |
| }, | |
| /** | |
| * We mostly need this so we know who the user is and how many | |
| * invites they have to keep tabs in the client side UI. | |
| * | |
| * @attribute user | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| user: { | |
| required: true | |
| } | |
| } | |
| }); | |
| /** | |
| * Handle the display of the password reset view. | |
| * | |
| * @class PasswordView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.PasswordView = Y.Base.create('bookie-password-view', Y.View, [], { | |
| _visible: false, | |
| /** | |
| * Bind all events thats the UI needs to function. | |
| * | |
| * @method _bind | |
| * @private | |
| * | |
| */ | |
| _bind: function () { | |
| Y.one('#show_password').on( | |
| 'click', | |
| this._show_password, | |
| this | |
| ); | |
| Y.one('form#password_reset').on( | |
| 'submit', | |
| this._change_password, | |
| this | |
| ); | |
| Y.one('#submit_password_change').on( | |
| 'click', | |
| this._change_password, | |
| this | |
| ); | |
| }, | |
| /** | |
| * Handle changing the password via an API call. | |
| * | |
| * @method _change_password | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _change_password: function (e) { | |
| var that = this, | |
| api_cfg = this.get('api_cfg'), | |
| api; | |
| e.preventDefault(); | |
| // hide the current message window | |
| Y.one('#password_msg').hide(); | |
| // add the password data to the cfg passed to the api | |
| api_cfg = Y.merge(api_cfg, { | |
| current_password: Y.one('#current_password').get('value'), | |
| new_password: Y.one('#new_password').get('value') | |
| }); | |
| api = new Y.bookie.Api.route.UserPasswordChange(api_cfg); | |
| api.call({ | |
| success: function (data, request) { | |
| that._show_message(data.message, true); | |
| that._reset_password(); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| that._show_message(data.error, false); | |
| that._reset_password(); | |
| } | |
| }); | |
| }, | |
| /** | |
| * Reset the form once we've successfully completed an an attempt to | |
| * change the password. | |
| * | |
| * @method _reset_password | |
| * | |
| */ | |
| _reset_password: function () { | |
| Y.one('#current_password').set('value', ''); | |
| Y.one('#new_password').set('value', ''); | |
| Y.one('#password_change').hide(true); | |
| // make sure we keep visible in sync | |
| this._visible = false; | |
| }, | |
| /** | |
| * Display any message based on if the request to change is successful | |
| * or ended in error. | |
| * | |
| * @method _show_message | |
| * @param {String} msg | |
| * @param {Boolean} success | |
| * | |
| */ | |
| _show_message: function (msg, success) { | |
| var msg_div = Y.one('#password_msg'); | |
| msg_div.setContent(msg); | |
| if (success) { | |
| msg_div.replaceClass('error', 'success'); | |
| } else { | |
| msg_div.replaceClass('success', 'error'); | |
| } | |
| msg_div.show(true); | |
| }, | |
| /** | |
| * Show the password change component. | |
| * | |
| * @method _show_password | |
| * @param {Event} e | |
| * | |
| */ | |
| _show_password: function (e) { | |
| var pass_div = Y.one('#password_change'); | |
| e.preventDefault(); | |
| // if the api key is showing and they click this, hide it | |
| if(this._visible) { | |
| pass_div.hide(true); | |
| this._visible = false; | |
| } else { | |
| this._visible = true; | |
| pass_div.show(true); | |
| } | |
| }, | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this._bind(); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| required: true | |
| } | |
| } | |
| }); | |
| /** | |
| * Handle the view ofr the account information. This is for changing the | |
| * user's name, email, etc. | |
| * | |
| * @class AccountInfoView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.AccountInfoView = Y.Base.create('bookie-account-info-view', Y.View, [], { | |
| /** | |
| * Bind all UI events for the UI. | |
| * | |
| * @method _bind | |
| * @private | |
| * | |
| */ | |
| _bind: function () { | |
| Y.one('#submit_account_change').on( | |
| 'click', | |
| this._update_account, | |
| this | |
| ); | |
| }, | |
| /** | |
| * Handle submitting the API to update the user's account information. | |
| * | |
| * @method _update_account | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _update_account: function (e) { | |
| var that = this, | |
| api_cfg = this.get('api_cfg'), | |
| api; | |
| e.preventDefault(); | |
| Y.one('#account_msg').hide(); | |
| var name = Y.one('#name').get('value'); | |
| var email = Y.one('#email').get('value'); | |
| // validate email and username | |
| if (!name || !email) { | |
| if (!name) { | |
| that._show_message( | |
| 'Please enter valid name', false); | |
| } else if (!email) { | |
| that._show_message( | |
| 'Please enter valid email address', false); | |
| } | |
| } else { | |
| // Add the password data to the cfg passed to the api. | |
| api_cfg = Y.merge(api_cfg, { | |
| name: Y.one('#name').get('value'), | |
| email: Y.one('#email').get('value') | |
| }); | |
| api = new Y.bookie.Api.route.UserAccountChange(api_cfg); | |
| api.call({ | |
| success: function (data, request) { | |
| that._show_message('Account updated...', true); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| console.log(data); | |
| console.log(response); | |
| that._show_message( | |
| 'Some error ocurred while making changes...', false | |
| ); | |
| } | |
| }); | |
| } | |
| }, | |
| /** | |
| * Handle showing the user any success for failure messages based on | |
| * the result of an attempt to update the user's account information. | |
| * | |
| * @method _show_message | |
| * @param {String} msg | |
| * @param {Boolean} success | |
| * @private | |
| * | |
| */ | |
| _show_message: function (msg, success) { | |
| var msg_div = Y.one('#account_msg'); | |
| msg_div.setContent(msg); | |
| if (success) { | |
| msg_div.replaceClass('error', 'success'); | |
| } else { | |
| msg_div.replaceClass('success', 'error'); | |
| } | |
| msg_div.show(true); | |
| }, | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this._bind(); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| required: true | |
| } | |
| } | |
| }); | |
| /** | |
| * Handle the UI for the login view. | |
| * | |
| * @class LoginView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.LoginView = Y.Base.create('bookie-login-view', Y.View, [], { | |
| _visible: false, | |
| /** | |
| * Bind all of the UI events for this html view. | |
| * | |
| * @method _bind | |
| * @private | |
| * | |
| */ | |
| _bind: function () { | |
| Y.one('#show_forgotten').on( | |
| 'click', | |
| this._show_forgotten, | |
| this | |
| ); | |
| Y.one('#submit_forgotten').on( | |
| 'click', | |
| this._forgotten, | |
| this | |
| ); | |
| }, | |
| /** | |
| * Clear out the login form. | |
| * | |
| * @method _clear | |
| * @private | |
| * | |
| */ | |
| _clear: function () { | |
| Y.one('#email').set('value', ''); | |
| }, | |
| /** | |
| * Show the forgotten password UI box for the user to use. | |
| * | |
| * @method _show_forgotten | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _show_forgotten: function (e) { | |
| var pass_div = Y.one('#forgotten_password'); | |
| e.preventDefault(); | |
| // if the api key is showing and they click this, hide it | |
| if(this._visible) { | |
| pass_div.hide(true); | |
| this._visible = false; | |
| } else { | |
| this._visible = true; | |
| pass_div.show(true); | |
| } | |
| }, | |
| /** | |
| * Handle a user submitting the form to reset their account because | |
| * they've forgotten the information. | |
| * | |
| * @method _forgotten | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _forgotten: function (e) { | |
| var that = this, | |
| api_cfg = this.get('api_cfg'), | |
| api; | |
| e.preventDefault(); | |
| // hide the current message window | |
| Y.one('#forgotten_msg').hide(); | |
| // add the password data to the cfg passed to the api | |
| api_cfg = Y.merge(api_cfg, { | |
| email: Y.one('#email').get('value') | |
| }); | |
| api = new Y.bookie.Api.route.SuspendUser(api_cfg); | |
| api.call({ | |
| success: function (data, request) { | |
| that._clear(); | |
| that._show_message(data.message, true); | |
| }, | |
| error: function (data, status_str, response, args) { | |
| console.log(data); | |
| console.log(response); | |
| var responseJSON = JSON.parse(response.response); | |
| that._show_message(responseJSON.error); | |
| } | |
| }); | |
| }, | |
| /** | |
| * Handle displaying success and failure messages to the user when | |
| * they submit the forgotten login information request. | |
| * | |
| * @method _show_message | |
| * @param {String} msg | |
| * @param {Boolean} success | |
| * @private | |
| * | |
| */ | |
| _show_message: function (msg, success) { | |
| var msg_div = Y.one('#forgotten_msg'); | |
| msg_div.setContent(msg); | |
| if (success) { | |
| msg_div.replaceClass('error', 'success'); | |
| } else { | |
| msg_div.replaceClass('success', 'error'); | |
| } | |
| msg_div.show(true); | |
| }, | |
| /** | |
| * General initializer | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this._bind(); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute api_cfg | |
| * @default undefined | |
| * @type Object | |
| * | |
| */ | |
| api_cfg: { | |
| required: true | |
| } | |
| } | |
| }); | |
| /** | |
| * View control for the options html pane in the extension. | |
| * | |
| * @class jptionsView | |
| * @extends Y.View | |
| * | |
| */ | |
| ns.OptionsView = Y.Base.create('bookie-options-view', Y.View, [], { | |
| /** | |
| * Setup the options form with data from our model to start out with. | |
| * | |
| * @method _init_form | |
| * @private | |
| * | |
| */ | |
| _init_form: function () { | |
| var opts = this.get('model'); | |
| Y.one('#api_url').set('value', opts.get('api_url')); | |
| Y.one('#api_username').set('value', opts.get('api_username')); | |
| Y.one('#api_key').set('value', opts.get('api_key')); | |
| if (opts.get('cache_content') === 'true') { | |
| Y.one('#cache_content').set('checked', true); | |
| } else { | |
| Y.one('#cache_content').set('checked', false); | |
| } | |
| }, | |
| /** | |
| * Use the API ping to check the settings the user wants to set. | |
| * | |
| * @method _ping_server | |
| * @param {Object} api_cfg For the settings to test our Ping agsinst | |
| * | |
| */ | |
| _ping_server: function (opts, callbacks) { | |
| var api = new Y.bookie.Api.route.Ping({ | |
| url: opts.api_url, | |
| username: opts.api_username, | |
| api_key: opts.api_key | |
| }); | |
| api.call(callbacks); | |
| }, | |
| /** | |
| * Display any message based on if the request to change is successful | |
| * or ended in error. | |
| * | |
| * @method _show_message | |
| * @param {String} msg | |
| * @param {Boolean} success | |
| * @private | |
| * | |
| */ | |
| _show_message: function (msg, success) { | |
| var msg_div = Y.one('#options_msg'); | |
| msg_div.setContent(msg); | |
| if (success) { | |
| msg_div.replaceClass('error', 'success'); | |
| } else { | |
| msg_div.replaceClass('success', 'error'); | |
| } | |
| msg_div.show(true); | |
| }, | |
| /** | |
| * Perform a sync of the bookmarks they user has stored by requesting | |
| * the list of hashes from the API on the server. | |
| * | |
| * @method _sync_bookmarks | |
| * @param {Event} e | |
| * @private | |
| * | |
| */ | |
| _sync_bookmarks: function (e) { | |
| var opts = this.get('model'), | |
| api, | |
| ind = new Y.bookie.Indicator({ | |
| target: Y.one('#sync') | |
| }); | |
| ind.render(); | |
| ind.show(); | |
| api = new Y.bookie.Api.route.Sync({ | |
| url: opts.get('api_url'), | |
| username: opts.get('api_username'), | |
| api_key: opts.get('api_key') | |
| }); | |
| // make the api calls | |
| api.call({ | |
| 'success': function (data, request) { | |
| Y.Array.each(data.hash_list, function (h) { | |
| // write out each hash to localStorage | |
| localStorage.setItem(h, 'true'); | |
| }); | |
| // finally stop the indicator from spinny spinny | |
| ind.hide(); | |
| } | |
| }); | |
| }, | |
| /** | |
| * Handle dispatching events for the UI. | |
| * | |
| * @attribute events | |
| * @type Object | |
| * | |
| * | |
| */ | |
| events: { | |
| // @event #form:submit | |
| 'form#form': { | |
| 'submit': 'update_options' | |
| }, | |
| '#sync_button': { | |
| 'click': '_sync_bookmarks' | |
| } | |
| }, | |
| template: '', | |
| /** | |
| * General initializer method. | |
| * | |
| * @method initializer | |
| * @param {Object} cfg | |
| * | |
| */ | |
| initializer: function (cfg) { | |
| this._init_form(); | |
| }, | |
| render: function () { | |
| // We need to make sure we hit the container so our events get | |
| // paste the lazy loading stage. | |
| this.get('container'); | |
| }, | |
| /** | |
| * Handle updating the options model with our selected information | |
| * whenthe form is submitted. | |
| * | |
| * @method update_options | |
| * @param {Event} e | |
| * | |
| */ | |
| update_options: function (e) { | |
| var that = this; | |
| e.preventDefault(); | |
| var msg_div = Y.one('#options_msg'), | |
| opts = this.get('model'), | |
| new_opts = {}; | |
| msg_div.hide(); | |
| // fetch the new values from the form and then update our model | |
| // with them. | |
| new_opts.api_url = Y.one('#api_url').get('value'); | |
| new_opts.api_username = Y.one('#api_username').get('value'); | |
| new_opts.api_key = Y.one('#api_key').get('value'); | |
| callbacks = { | |
| success: function (data, response) { | |
| // make sure we were successful | |
| if (data.success) { | |
| opts.set('api_url', Y.one('#api_url').get('value')); | |
| opts.set('api_username', Y.one('#api_username').get('value')); | |
| opts.set('api_key', Y.one('#api_key').get('value')); | |
| if (Y.one('#cache_content').get('checked')) { | |
| opts.set('cache_content', 'true'); | |
| } else { | |
| opts.set('cache_content', 'false'); | |
| } | |
| // Set the flag so that it doesn't bug the user | |
| // for the configuration every single time. | |
| chrome.storage.local.set({ | |
| "optionsConfigured": true | |
| }); | |
| // Now that we have updated the settings in memory, | |
| // do the same with offline chrome.storage | |
| opts.save(); | |
| that._show_message('Saved your settings...', true); | |
| } else { | |
| that._show_message('I could not Ping the server with your settings. Server said: ' + | |
| data.message, false); | |
| } | |
| }, | |
| error: function (data, status_str, response, args) { | |
| that._show_message('I could not Ping the server with your settings. Server said: ' + | |
| data.message, false); | |
| } | |
| }; | |
| // Let's do all this based on the status of the ping attempt; | |
| this._ping_server(new_opts, callbacks); | |
| } | |
| }, { | |
| ATTRS: { | |
| /** | |
| * @attribute container | |
| * @default Y.Node the body of the document | |
| * @type Y.Node | |
| * | |
| */ | |
| container: { | |
| valueFn: function () { | |
| return Y.one('body'); | |
| } | |
| }, | |
| /** | |
| * @attribute model | |
| * @default Y.bookie.OptionModel | |
| * @type Y.bookie.OptionModel | |
| * | |
| */ | |
| model: { | |
| valueFn: function () { | |
| return new Y.bookie.OptionsModel(); | |
| } | |
| } | |
| } | |
| }); | |
| }, '0.1.0', { | |
| requires: [ | |
| 'base', | |
| 'bookie-api', | |
| 'bookie-indicator', | |
| 'bookie-model', | |
| 'bookie-rsswatch', | |
| 'bookie-tagcontrol', | |
| 'handlebars', | |
| 'substitute', | |
| 'transition', | |
| 'view' | |
| ] | |
| }); |