sports_db 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/app/assets/javascripts/core/App.js +256 -0
- data/app/assets/javascripts/core/BaseView.js +13 -10
- data/app/assets/javascripts/core/History.js +2 -2
- data/app/assets/javascripts/core/Mock.js +7 -9
- data/app/assets/javascripts/core/Timer.js +3 -1
- data/app/assets/javascripts/core/View.js +2 -1
- data/app/assets/javascripts/core/utilities.js +8 -6
- data/app/assets/javascripts/plugins/articles.js +195 -0
- data/app/assets/javascripts/plugins/assert.js +1 -1
- data/app/assets/javascripts/plugins/calnav.js +2 -1
- data/app/assets/javascripts/plugins/collapsible.js +1 -0
- data/app/assets/javascripts/plugins/delayed_load.js +42 -0
- data/app/assets/javascripts/plugins/flash.js +1 -1
- data/app/assets/javascripts/plugins/jquery.zumobi-0.2.js +2 -3
- data/app/assets/javascripts/plugins/loading.js +1 -0
- data/app/assets/javascripts/plugins/resizeable.js +1 -0
- data/app/assets/javascripts/plugins/zepto.filterable.js +1 -13
- data/app/assets/javascripts/plugins/zepto.preload.js +2 -1
- data/app/assets/javascripts/plugins/zepto.tabs.js +3 -3
- data/app/assets/stylesheets/_articles.css.scss +153 -0
- data/app/assets/stylesheets/_base.css.scss +16 -1
- data/app/assets/stylesheets/_filterable.css.scss +3 -11
- data/app/assets/stylesheets/_gradients.css.scss +26 -0
- data/app/assets/stylesheets/_logo.css.scss +12 -0
- data/app/assets/stylesheets/_table_base.scss +40 -4
- data/app/assets/stylesheets/_table_collapsible.css.scss +24 -0
- data/app/assets/stylesheets/_tabs.css.scss +59 -0
- data/app/assets/stylesheets/_toolbar.css.scss +38 -0
- data/app/models/twitter.rb +5 -4
- data/app/views/shared/_articles.html.erb +66 -0
- data/lib/sports_db/version.rb +1 -1
- metadata +12 -2
@@ -0,0 +1,256 @@
|
|
1
|
+
var Application = Class.extend({
|
2
|
+
initialize: function() {
|
3
|
+
|
4
|
+
this.views = {};
|
5
|
+
this.params = {};
|
6
|
+
this.cache = {};
|
7
|
+
this.currentView = null;
|
8
|
+
this.clientCallbackHandlers = [];
|
9
|
+
this.wrapper = $('#view_wrapper');
|
10
|
+
this.buffer = $('#tmp');
|
11
|
+
this.footer = $('#footer');
|
12
|
+
this.client = {};
|
13
|
+
this.setClientParams();
|
14
|
+
|
15
|
+
// Get hash params
|
16
|
+
if (window.location.hash) {
|
17
|
+
this.params = $.serialize(location.hash.slice(1));
|
18
|
+
}
|
19
|
+
|
20
|
+
this.params = $.extend(window.CONFIG, this.params);
|
21
|
+
|
22
|
+
if (!this.params.clientSupportsClose) {
|
23
|
+
this.app_is_initializing = true;
|
24
|
+
}
|
25
|
+
|
26
|
+
// Start timer for game updates
|
27
|
+
// TODO only run this on game views
|
28
|
+
this.timer = new Timer($.proxy(this._fireTimerEvent, this), this.params.defaultTimer);
|
29
|
+
this.timer.start();
|
30
|
+
},
|
31
|
+
setClientParams: function() {
|
32
|
+
var q = $.deserialize( location.search.slice(1) );
|
33
|
+
|
34
|
+
$.assert(q.client, '`client` param is required.');
|
35
|
+
$.assert(q.version, '`version` param is required.');
|
36
|
+
|
37
|
+
this.client[q.client] = true;
|
38
|
+
// this.client.version_major = q.version.split('.')[0];
|
39
|
+
// this.client.version_minor = q.version.split('.')[1];
|
40
|
+
|
41
|
+
$('html').addClass('client_'+q.client);
|
42
|
+
},
|
43
|
+
// Fire a timer event
|
44
|
+
_fireTimerEvent: function() {
|
45
|
+
$(document.body).trigger('timerReachInterval');
|
46
|
+
},
|
47
|
+
// Call the view if the method exists
|
48
|
+
_onTimerReachedInterval: function() {
|
49
|
+
var view = this.currentView;
|
50
|
+
if (view && view._onTimerReachedInterval) {
|
51
|
+
view._onTimerReachedInterval.call(view);
|
52
|
+
}
|
53
|
+
},
|
54
|
+
// Register a view constructor under a specific name. If a link in the application has
|
55
|
+
// a parameter named "view" that points to a registered view name, then the `Application`
|
56
|
+
// will load that view. Optionally, you can pass in parameters, and these will be merged
|
57
|
+
// with any other parameters in the link that triggers view loading (parameters in the
|
58
|
+
// link override parameters in the registration binding). This allows you to bind the
|
59
|
+
// same view under different names with different parameters in order to parameterize
|
60
|
+
// its behavior.
|
61
|
+
//
|
62
|
+
// @param {Object} name
|
63
|
+
// @param {Object} constructor
|
64
|
+
// @param {Object} params (optional)
|
65
|
+
registerView: function(name, constructor, params) {
|
66
|
+
this.views[name] = { constructor: constructor, params: (params || {}) };
|
67
|
+
},
|
68
|
+
// Stash a view, i.e. change the url to something meaningful, but do not show the
|
69
|
+
// view based on this URL change. This is needed in cases where the device goes to
|
70
|
+
// sleep, and then reloads upon awakening.
|
71
|
+
stashView: function(params) {
|
72
|
+
$.assert(!this.params.clientSupportsClose, "App should not be using Application.stashView method");
|
73
|
+
|
74
|
+
// TODO kill this method in all apps. Need client support.
|
75
|
+
if (!this.params.clientSupportsClose) {
|
76
|
+
console.log('** Application.stashView');
|
77
|
+
var local = {};
|
78
|
+
local.view = params.view;
|
79
|
+
if (params.filter) { local.filter = params.filter; }
|
80
|
+
if (params.key) { local.key = params.key; }
|
81
|
+
local.stash = true;
|
82
|
+
var url = "#" + $.serialize(local);
|
83
|
+
|
84
|
+
document.location = url;
|
85
|
+
}
|
86
|
+
},
|
87
|
+
// Show a view based on the supplied parameters. The only required parameter is "view"
|
88
|
+
// which must reference a valid view name.
|
89
|
+
//
|
90
|
+
// @param {Object} params
|
91
|
+
showView: function(params) {
|
92
|
+
console.log('$$ Application.showView');
|
93
|
+
$.assert(params.view, 'No view specified (use /' + this.params.serverPath + '/#view=<viewName>)');
|
94
|
+
|
95
|
+
var binding = this.views[params.view];
|
96
|
+
|
97
|
+
$.assert(binding, params.view + ' is not a registered view name. Did you add it to views.js?');
|
98
|
+
|
99
|
+
// Merge binding parameters (from views.js) into any parameters that were supplied in the URL
|
100
|
+
for (var prop in binding.params) {
|
101
|
+
if (typeof params[prop] === 'undefined') {
|
102
|
+
params[prop] = binding.params[prop];
|
103
|
+
}
|
104
|
+
}
|
105
|
+
var view = new binding.constructor(params, this);
|
106
|
+
$.assert(view.create, params.view + ' does not have a create method and is not a valid view');
|
107
|
+
|
108
|
+
view.create(params);
|
109
|
+
},
|
110
|
+
// When the view is done initializing, it must call this method.
|
111
|
+
appendView: function(newView, cached) {
|
112
|
+
console.log('$$ Application.appendView');
|
113
|
+
|
114
|
+
// Save the scroll state of the old view
|
115
|
+
if (this.currentView) {
|
116
|
+
this.currentView.params.pageYOffset = window.pageYOffset;
|
117
|
+
}
|
118
|
+
|
119
|
+
// Re-assign this.currentView to the new view.
|
120
|
+
// Add it to the Application.cache.
|
121
|
+
this.currentView = this.cache[History.currentHash()] = newView;
|
122
|
+
|
123
|
+
// Mark the view as cached
|
124
|
+
if (cached) {
|
125
|
+
this.currentView.params.cached = true;
|
126
|
+
// NBA3 TODO use the param
|
127
|
+
$(newView.element).addClass('cached');
|
128
|
+
}
|
129
|
+
|
130
|
+
this.wrapper.empty().append(newView.element);
|
131
|
+
|
132
|
+
this.currentView._evaluateDataAttribute();
|
133
|
+
|
134
|
+
// Set scroll position.
|
135
|
+
window.scrollTo(0, (this.currentView.params.pageYOffset || 0));
|
136
|
+
|
137
|
+
// Reset metrics flag
|
138
|
+
this.currentView.params.hasSentMetrics = false;
|
139
|
+
|
140
|
+
// Allow the view to add behavior.
|
141
|
+
this.currentView.onViewChanged(this.currentView.params, this);
|
142
|
+
|
143
|
+
// Send Metrics
|
144
|
+
if (!this.currentView.params.skip_metrics === true) {
|
145
|
+
this.sendMetrics(this.currentView);
|
146
|
+
}
|
147
|
+
|
148
|
+
// Let plugins know about the view being appended
|
149
|
+
$(document.body).trigger('Application:viewAppended', [this.currentView.params]);
|
150
|
+
|
151
|
+
// Show the footer
|
152
|
+
if (this.footer) {
|
153
|
+
this.footer.show();
|
154
|
+
}
|
155
|
+
|
156
|
+
// Hide the loader
|
157
|
+
$.hideLoader();
|
158
|
+
},
|
159
|
+
sendMetrics: function(view) {
|
160
|
+
Client.notify({
|
161
|
+
'action': view.getAction(),
|
162
|
+
'buttons': view.getButtons(),
|
163
|
+
'filter': view.getFilter(),
|
164
|
+
'metric': view.getMetric(),
|
165
|
+
'refreshAd': view.shouldRefreshAd(),
|
166
|
+
'section': view.getSection(),
|
167
|
+
'title': view.getTitle()
|
168
|
+
});
|
169
|
+
view.params.hasSentMetrics = true;
|
170
|
+
},
|
171
|
+
storage: function() {
|
172
|
+
// Feature detect localStorage + local reference
|
173
|
+
var storage, fail, uid;
|
174
|
+
|
175
|
+
try {
|
176
|
+
uid = new Date;
|
177
|
+
(storage = window.localStorage).setItem(uid, uid);
|
178
|
+
fail = storage.getItem(uid) != uid;
|
179
|
+
storage.removeItem(uid);
|
180
|
+
fail && (storage = false);
|
181
|
+
} catch(e) {}
|
182
|
+
|
183
|
+
if (storage) {
|
184
|
+
console.log('=> localStorage is available');
|
185
|
+
return storage;
|
186
|
+
} else {
|
187
|
+
console.log('=> localStorage is NOT available');
|
188
|
+
return null;
|
189
|
+
}
|
190
|
+
},
|
191
|
+
// The web application is receiving a callback from the client to set a value or execute some
|
192
|
+
// behavior. If the view has an `onClientCallback` method, this will be executed first. It can
|
193
|
+
// cancel any further event handling by returning `true`. Otherwise, the application sends the
|
194
|
+
// event to all of the `clientCallbackHandlers` that are registered with the application, in the
|
195
|
+
// order they were registered.
|
196
|
+
//
|
197
|
+
// @param {String} name
|
198
|
+
// @param {Object} value
|
199
|
+
onClientCallback: function(name, value) {
|
200
|
+
var handled = false;
|
201
|
+
var view = this.currentView;
|
202
|
+
if (view && view.onClientCallback) {
|
203
|
+
handled = view.onClientCallback.call(view, name, value);
|
204
|
+
}
|
205
|
+
if (!handled) {
|
206
|
+
this.clientCallbackHandlers.forEach(function(handler) {
|
207
|
+
handler.call(this, name, value);
|
208
|
+
}, this);
|
209
|
+
}
|
210
|
+
},
|
211
|
+
// load a view from cache or the server when we get a hashchange event
|
212
|
+
_onHashChange: function(event, memo) {
|
213
|
+
if (!this.params.clientSupportsClose) {
|
214
|
+
// If the app is not initializing, and the view is stashed, do not do anything
|
215
|
+
if (!this.app_is_initializing && memo.stash) {
|
216
|
+
console.log('=> App is not initializing & a view is stashed. RETURN');
|
217
|
+
return;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
$.assert(memo.view, 'The requested URL could not be found. { href: ' + location.href + ' }');
|
222
|
+
|
223
|
+
var view = this.cache[History.currentHash()];
|
224
|
+
if (view) {
|
225
|
+
console.log('@@ Getting view from cache.');
|
226
|
+
view.params.cached = true;
|
227
|
+
this.appendView(view, true);
|
228
|
+
} else {
|
229
|
+
console.log('@@ Creating view from scratch.');
|
230
|
+
this.showView(memo);
|
231
|
+
}
|
232
|
+
|
233
|
+
if (!this.params.clientSupportsClose) {
|
234
|
+
this.app_is_initializing = false;
|
235
|
+
}
|
236
|
+
},
|
237
|
+
// Initializes application functionality on page ready, and kicks off loading the view.
|
238
|
+
//
|
239
|
+
// @private
|
240
|
+
_onReady: function() {
|
241
|
+
$(document.body)
|
242
|
+
.on('hashchange', $.proxy(Application._onHashChange, this))
|
243
|
+
.on('timerReachInterval', $.proxy(Application._onTimerReachedInterval, this))
|
244
|
+
.list_hl('tr[href]', function(e, el) {
|
245
|
+
History.add( $.deserialize( el.attr('href').slice(1) ) );
|
246
|
+
});
|
247
|
+
}
|
248
|
+
});
|
249
|
+
|
250
|
+
// Singleton.
|
251
|
+
console.log('@@@@ Starting Application');
|
252
|
+
Application = new Application();
|
253
|
+
|
254
|
+
Zepto(function($) {
|
255
|
+
Application._onReady();
|
256
|
+
});
|
@@ -1,9 +1,10 @@
|
|
1
|
+
/*global View Application unescape */
|
1
2
|
// A basic view implementation that expects an `URL` to be passed as one of the parameters
|
2
3
|
// to the view; it will format that `URL` using any other parameters, and use it to retrieve
|
3
4
|
// an `HTML` fragment from the server. This is only one of many strategies that could be
|
4
5
|
// followed to create views, of course. It also assumes that the parameters object will
|
5
6
|
// get a title property.
|
6
|
-
|
7
|
+
window.BaseView = View.extend({
|
7
8
|
// Subclasses must ensure there is an url property to the parameter object passed
|
8
9
|
// into this superconstructor, i.e.:
|
9
10
|
//
|
@@ -71,21 +72,21 @@ var BaseView = View.extend({
|
|
71
72
|
console.log('$$ BaseView.create(): Not appending autoupdate view. We are no longer on that view!');
|
72
73
|
} else {
|
73
74
|
// NBA3 only
|
74
|
-
if ($.highResifyLogosForRetinaAndAndroid) {
|
75
|
-
|
76
|
-
}
|
75
|
+
// if ($.highResifyLogosForRetinaAndAndroid) {
|
76
|
+
// response = $.highResifyLogosForRetinaAndAndroid(response);
|
77
|
+
// }
|
77
78
|
|
78
79
|
// Get a node rather than plain HTML
|
79
80
|
this.element = Application.buffer.html(response).find('div').get(0);
|
80
81
|
Application.appendView(this);
|
81
82
|
|
82
83
|
// NBA3 only
|
83
|
-
if ($.delayedLoad) {
|
84
|
-
|
85
|
-
}
|
84
|
+
// if ($.delayedLoad) {
|
85
|
+
// $.delayedLoad();
|
86
|
+
// }
|
86
87
|
}
|
87
88
|
}, this),
|
88
|
-
error: function(
|
89
|
+
error: function() {
|
89
90
|
$.hideLoader();
|
90
91
|
$.flash("A network error occurred.", Application.currentView.params, true);
|
91
92
|
throw new Error('An error occurred.');
|
@@ -112,8 +113,10 @@ var BaseView = View.extend({
|
|
112
113
|
var data = JSON.parse(params);
|
113
114
|
|
114
115
|
for (var key in data) {
|
115
|
-
|
116
|
-
|
116
|
+
if (data.hasOwnProperty(key)) {
|
117
|
+
// If you escape a non-string value, it is first converted to a string, which we don't want
|
118
|
+
this.params[key] = (typeof data[key] === "string") ? unescape(data[key]) : data[key];
|
119
|
+
}
|
117
120
|
}
|
118
121
|
}
|
119
122
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
// A very simple history implementation. Generates events on the `document.body` element when the
|
2
2
|
// hash changes, and includes a parsed object of parameters or a string from the hash.
|
3
3
|
|
4
|
-
|
4
|
+
window.History = (function() {
|
5
5
|
|
6
6
|
var currentHash = null;
|
7
7
|
|
@@ -40,6 +40,6 @@ var History = (function() {
|
|
40
40
|
currentHash: function() {
|
41
41
|
return getHash();
|
42
42
|
}
|
43
|
-
}
|
43
|
+
};
|
44
44
|
|
45
45
|
})();
|
@@ -1,7 +1,8 @@
|
|
1
|
+
/*global Class Application Client MOCK_FAVES_CONFIG */
|
1
2
|
//= require core/mock_config.js
|
2
3
|
|
3
4
|
// Mock client interface
|
4
|
-
|
5
|
+
window.Mock = Class.extend({
|
5
6
|
initialize: function(client) {
|
6
7
|
this.client = client;
|
7
8
|
window.addEventListener("load", $.proxy(this._makeToolbar, this), true);
|
@@ -10,12 +11,7 @@ var Mock = Class.extend({
|
|
10
11
|
var toolbar = document.createElement("div");
|
11
12
|
toolbar.id = "mock-toolbar-container";
|
12
13
|
// CSS is set in `mock.css`
|
13
|
-
toolbar.innerHTML = "<div id=
|
14
|
-
<div id='mock-left'></div>\
|
15
|
-
<div id='mock-center'></div>\
|
16
|
-
<div id='mock-right'></div>\
|
17
|
-
</div>";
|
18
|
-
|
14
|
+
toolbar.innerHTML = "<div id=mock-toolbar><div id=mock-left></div><div id=mock-center></div><div id=mock-right></div></div>";
|
19
15
|
document.body.insertBefore(toolbar, document.body.firstChild);
|
20
16
|
this.toolbar = toolbar;
|
21
17
|
}
|
@@ -26,7 +22,7 @@ var Mock = new Mock(Client);
|
|
26
22
|
Client.makeButtons = function(str) {
|
27
23
|
if (!str) return;
|
28
24
|
var specs = str.split(":");
|
29
|
-
if (specs.length
|
25
|
+
if (specs.length !== 2) {
|
30
26
|
alert("There should be 2 segments to a buttons specification");
|
31
27
|
} else {
|
32
28
|
makeButtonsForSection(specs[0], "mock-left");
|
@@ -76,7 +72,9 @@ Client.notify = function(obj) {
|
|
76
72
|
if (window.console && window.console.log) {
|
77
73
|
var arr = [];
|
78
74
|
for (var prop in obj) {
|
79
|
-
|
75
|
+
if (obj.hasOwnProperty(prop)) {
|
76
|
+
arr.push(prop + ": " + obj[prop]);
|
77
|
+
}
|
80
78
|
}
|
81
79
|
console.log("))) Client.notify({ " + arr.join(", ") + " })");
|
82
80
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/*global Class */
|
1
2
|
// If your view implements an initialization function, that function will be passed a parameter
|
2
3
|
// object containing all the query parameters in the URL that triggered the view's creation, plus
|
3
4
|
// all of those values that were assigned to the view when it was registered and bound to a name.
|
@@ -5,7 +6,7 @@
|
|
5
6
|
// `this.params`). At the end of a view's create method, it should have inserted a dom element into
|
6
7
|
// the body of the page. This will be assigned as the "element" property to the view by the application,
|
7
8
|
// as it needs to be referenced outside your view class.
|
8
|
-
|
9
|
+
window.View = Class.extend({
|
9
10
|
// This method should create (by any means desirable) a DOM element and insert it into the page.
|
10
11
|
// Our base implementation queries for an HTML fragment from the server, but this is up to
|
11
12
|
// your view implementation.
|
@@ -21,27 +21,29 @@ String.prototype.format = function(hash, translate_key) {
|
|
21
21
|
translate_key = translate_key || false;
|
22
22
|
var s = this;
|
23
23
|
for (var key in hash) {
|
24
|
-
|
25
|
-
|
24
|
+
if (hash.hasOwnProperty(key)) {
|
25
|
+
var re = new RegExp('\\{' + (key) + '\\}','gm');
|
26
|
+
s = s.replace(re, hash[key]);
|
27
|
+
}
|
26
28
|
}
|
27
29
|
return s;
|
28
|
-
}
|
30
|
+
};
|
29
31
|
|
30
32
|
window.$id = function(id) {
|
31
33
|
return document.getElementById(id);
|
32
|
-
}
|
34
|
+
};
|
33
35
|
|
34
36
|
// Capitalize the first character of a string.
|
35
37
|
String.prototype.capitalize = function() {
|
36
38
|
return this.charAt(0).toUpperCase() + this.substr(1).toLowerCase();
|
37
|
-
}
|
39
|
+
};
|
38
40
|
|
39
41
|
// zepto/querySelector, understandably, can't deal with periods in the id attr.
|
40
42
|
String.prototype.dotToBar = function() {
|
41
43
|
return this.replace(/\./g,"_");
|
42
44
|
};
|
43
45
|
|
44
|
-
|
46
|
+
window.macrojungle = function(tmpl) {
|
45
47
|
// This is kind of stupid.
|
46
48
|
// But at least it's only written once.
|
47
49
|
var html = $('#tmp').empty().microjungle(tmpl).html();
|
@@ -0,0 +1,195 @@
|
|
1
|
+
;(function($){
|
2
|
+
|
3
|
+
var getMetricPrefix = function(view) {
|
4
|
+
var metric = view.getMetric();
|
5
|
+
if (view.params.view === 'team') {
|
6
|
+
metric += '/News';
|
7
|
+
}
|
8
|
+
return metric;
|
9
|
+
};
|
10
|
+
|
11
|
+
$.articles = function(opts) {
|
12
|
+
var view = Application.currentView;
|
13
|
+
var defaults = {
|
14
|
+
'params': {},
|
15
|
+
'id': null
|
16
|
+
};
|
17
|
+
opts = $.extend(defaults, opts);
|
18
|
+
|
19
|
+
var show_article = function(params) {
|
20
|
+
if (params.id.substring(0) !== "#") {
|
21
|
+
params.id = "#"+params.id;
|
22
|
+
}
|
23
|
+
|
24
|
+
view.params.activeArticle = params.id;
|
25
|
+
|
26
|
+
$('.summaries,#filter,.article_wrapper,#footer,#team_heading,#team_tabs').hide();
|
27
|
+
$(params.id).show();
|
28
|
+
|
29
|
+
window.scrollTo(0,1);
|
30
|
+
|
31
|
+
if (Application.params.clientSupportsClose) {
|
32
|
+
Client.notify({
|
33
|
+
'buttons': ($('.summary_link').size() < 2) ? 'Close:' : 'Close:NudgeNav',
|
34
|
+
'metric': getMetricPrefix(view) + '/Detail',
|
35
|
+
'refreshAd': true
|
36
|
+
});
|
37
|
+
} else {
|
38
|
+
// Makes the back button to work
|
39
|
+
Application.stashView(view.params);
|
40
|
+
Client.notify({
|
41
|
+
"buttons": view.params.should_have_buttons,
|
42
|
+
"metric": getMetricPrefix(view) + "/Detail",
|
43
|
+
"title": view.getTitle(),
|
44
|
+
'refreshAd': true
|
45
|
+
});
|
46
|
+
}
|
47
|
+
|
48
|
+
};
|
49
|
+
|
50
|
+
var handlers = function() {
|
51
|
+
$('.resizeable').resizeable();
|
52
|
+
|
53
|
+
$('.summaries').list_hl('.summary_link', function(e, el) {
|
54
|
+
view.params.pageYOffset = window.pageYOffset;
|
55
|
+
show_article({ 'id': el.attr('for') });
|
56
|
+
});
|
57
|
+
|
58
|
+
$('.share_btn')
|
59
|
+
.off('click')
|
60
|
+
.on('click', function(e) {
|
61
|
+
var $this = $(this);
|
62
|
+
var c = {
|
63
|
+
'title': $this.data('title'),
|
64
|
+
'summary': $this.data('summary'),
|
65
|
+
'url': $this.data('url'),
|
66
|
+
'platform': Application.client.ios ? 'iOS' : 'Android',
|
67
|
+
'img': $this.data('fbimg'),
|
68
|
+
'shortName': Application.params.shortName,
|
69
|
+
'longName': Application.params.longName,
|
70
|
+
'sharingUrl': Application.params.sharingUrl
|
71
|
+
};
|
72
|
+
var email_message_tmpl = [
|
73
|
+
['p',
|
74
|
+
'I found "{title}" and thought you might be interested: '.format(c),
|
75
|
+
['a', {'href': '@SHORTENED_URL@'}, '@SHORTENED_URL@']
|
76
|
+
],
|
77
|
+
['p', '--'],
|
78
|
+
['p', 'Get more from {longName} while on the go. '.format(c),
|
79
|
+
['a', {'href': '{sharingUrl}'.format(c)}, 'Download'],
|
80
|
+
' it now.'
|
81
|
+
]
|
82
|
+
];
|
83
|
+
var twitter_message = '"{title}" @SHORTENED_URL@ via {shortName}'.format(c);
|
84
|
+
var email_subject = '"{title}" via {longName} for {platform}'.format(c);
|
85
|
+
|
86
|
+
var share_params = {
|
87
|
+
'action': 'share',
|
88
|
+
'twitter_message': twitter_message,
|
89
|
+
'facebook_name': c.title,
|
90
|
+
'facebook_message': c.summary,
|
91
|
+
'facebook_image': c.img,
|
92
|
+
'email_subject': email_subject,
|
93
|
+
'email_message': macrojungle(email_message_tmpl),
|
94
|
+
'url': c.url
|
95
|
+
};
|
96
|
+
// Don't send these to iOS. See bug 24061.
|
97
|
+
if (Application.client.android) {
|
98
|
+
share_params.title = c.title;
|
99
|
+
share_params.excerpt = c.summary;
|
100
|
+
if (c.img) {
|
101
|
+
share_params.img_url = c.img;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
Client.notify(share_params);
|
105
|
+
});
|
106
|
+
};
|
107
|
+
var handle_notifications = function(params) {
|
108
|
+
params.notifs = params.notifs || [];
|
109
|
+
|
110
|
+
// Check if this notif has been viewed before.
|
111
|
+
if (params.notifs[params.digest]) return;
|
112
|
+
|
113
|
+
if ($('#'+params.digest).size() > 0) {
|
114
|
+
Client.notify({
|
115
|
+
'metric': getMetricPrefix(view) + '/Notification'
|
116
|
+
});
|
117
|
+
show_article({ 'id': params.digest });
|
118
|
+
} else {
|
119
|
+
if (Application.params.clientSupportsAlert) {
|
120
|
+
Client.notify({
|
121
|
+
'action': 'alert',
|
122
|
+
'heading': 'An error occurred',
|
123
|
+
'text': 'The requested article could not be found.'
|
124
|
+
});
|
125
|
+
} else {
|
126
|
+
alert('The requested article could not be found.');
|
127
|
+
}
|
128
|
+
}
|
129
|
+
// Mark that this notif has been viewed, or even though
|
130
|
+
// the digest was bogus, mark that it was read so
|
131
|
+
// the user isn't told the article doesn't exist over and over.
|
132
|
+
params.notifs[params.digest] = true;
|
133
|
+
};
|
134
|
+
|
135
|
+
// This is used with the Nudge Nav.
|
136
|
+
if (opts.id) {
|
137
|
+
show_article({ 'id': opts.id });
|
138
|
+
// This is the standard initialization.
|
139
|
+
} else {
|
140
|
+
$('.article_wrapper').hide();
|
141
|
+
$('.summaries,#filter,#footer,#team_heading,#team_tabs').show();
|
142
|
+
|
143
|
+
handlers();
|
144
|
+
|
145
|
+
if (opts.params.digest) {
|
146
|
+
handle_notifications(opts.params);
|
147
|
+
}
|
148
|
+
if (!Application.params.clientSupportsClose) {
|
149
|
+
Application.currentView.params.should_have_buttons = ($('.summary_link').size() < 2) ? "Back:" : "Back:NudgeNav";
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
};
|
154
|
+
|
155
|
+
// Supports nudge navigation via client application.
|
156
|
+
// Navigation loops.
|
157
|
+
$.articlesClientCallback = function(name, value) {
|
158
|
+
var view = Application.currentView;
|
159
|
+
var params = view.params;
|
160
|
+
var $article = $(params.activeArticle);
|
161
|
+
|
162
|
+
if (name === 'close') {
|
163
|
+
$('.article_wrapper').hide();
|
164
|
+
$('.summaries,#filter,#footer,#team_heading,#team_tabs').show();
|
165
|
+
|
166
|
+
window.scrollTo(0, view.params.pageYOffset);
|
167
|
+
|
168
|
+
Client.notify({
|
169
|
+
'buttons': "Back:",
|
170
|
+
'metric': getMetricPrefix(view),
|
171
|
+
'refreshAd': true
|
172
|
+
});
|
173
|
+
}
|
174
|
+
|
175
|
+
if (name === 'nudge') {
|
176
|
+
if (value === 'next' && $article.data('next')) {
|
177
|
+
$.articles({
|
178
|
+
'params': params,
|
179
|
+
'id': $article.data('next')
|
180
|
+
});
|
181
|
+
} else if (value === 'prev' && $article.data('prev')) {
|
182
|
+
$.articles({
|
183
|
+
'params': params,
|
184
|
+
'id': $article.data('prev')
|
185
|
+
});
|
186
|
+
} else {
|
187
|
+
$.articles({
|
188
|
+
'params': params,
|
189
|
+
'id': $('.article_wrapper').first().attr('id')
|
190
|
+
});
|
191
|
+
}
|
192
|
+
}
|
193
|
+
};
|
194
|
+
|
195
|
+
})(Zepto);
|
@@ -1,9 +1,10 @@
|
|
1
|
+
/*global Application $id */
|
1
2
|
// Behavior for calendar (schedule) navigation.
|
2
3
|
;(function($){
|
3
4
|
$.calnav = function(){
|
4
5
|
$('.calnav .item[href]')
|
5
6
|
.off('click')
|
6
|
-
.on('click', function(
|
7
|
+
.on('click', function() {
|
7
8
|
Application.showView(
|
8
9
|
$.deserialize(this.getAttribute('href'))
|
9
10
|
);
|