sports_db 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
);
|