ああ、
Placemaker.js
いくつかの実験の後、複数の同時リクエストを処理できないという問題を突き止めました。クロージャの問題を克服してループ生成データを記憶できると考えたくなるかもしれませんが、これはうまくいきません。修正を適用する必要があるためPlacemaker
、jQuery プラグインとしてリファクタリングすることにしました。promise
jQuery は、メソッドからa を返す可能性を提供し、getPlaces
jQuery のネイティブなどと同様にし$.ajax()
ます$.get()
。
ヤフー!jQuery プラグインとしての Placemaker.js
/* ******************************************************************************
* Yahoo! Placemaker.js factored as a jQuery Plugin
* ******************************************************************************
* by Beetroot-Beetroot: http://stackoverflow.com/users/1142252/beetroot-beetroot
* ******************************************************************************
* For example of usage, see : http://stackoverflow.com/questions/12253544/
* ******************************************************************************
* All rights reserved
* Please keep this attribution intact
* ******************************************************************************
*/
(function($){
// **********************************
// ***** Start: Private Members *****
var pluginName = 'Placemaker';
var config = {
appID: ''
}
// ***** Fin: Private Members *****
// ********************************
// *********************************
// ***** Start: Public Methods *****
var methods = {
config: function(obj) {
$.extend(config, obj);
},
getPlaces: function(data) {
var that = this;//jQuery object
var def = new $.Deferred();
if(config.appID === '') {
def.rejectWith(this, [{message: pluginName + ' plugin application ID is not set'}]);
return def.promise();
}
var query = [
'select * from geo.placemaker where documentContent="' + data.text + '" and documentType="text/plain"'
];
if(data.locale) {
query.push('and inputLanguage="' + data.locale + '"');
}
query.push('and appid="' + config.appID + '"');
var url = [
'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(query.join(' ')),
'format=json',
'env=http%3A%2F%2Fdatatables.org%2Falltables.env',
'callback=?' // callback=Placemaker.retrieve ????
];
$.ajax({
url: url.join('&'),
type: 'GET',
dataType: 'JSON',
cache: false
}).done(function(o) {
if(o.query && o.query.results && o.query.results.matches) {
def.resolveWith(that, [o.query.results.matches, data]);
}
else {
def.rejectWith(that, [{message:'no locations found'}]);
}
}).fail(function(jqXHR, textStatus, errorThrown) {
def.rejectWith(that, [{message: textStatus}]);
});
return def.promise();
}
};
// ***** Fin: Public Methods *****
// *******************************
// *****************************
// ***** Start: Supervisor *****
$.fn[pluginName] = function( method ) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || !method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist in jQuery.' + pluginName );
}
};
// ***** Fin: Supervisor *****
// ***************************
})( jQuery );
appID の設定
You can hard-code your appID in your own copy of the plugin or set it like this :
$().Placemaker('config', {'appID': '..........'});
.Placemaker()
jQuery オブジェクトで呼び出す必要があることに注意してください。「config」メソッドの場合は、どのセレクターでも機能するため、空の jQuery オブジェクトで$()
十分です。
プラグインの使用
プラグイン呼び出しを含む残りのコードは、次のようになります。
$(function() {
// *** fixed data ***
var mapOptions = {
center: new google.maps.LatLng(35.74651, -39.46289),
zoom: 2,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var templates = [];
templates[0] = '<div><h2 class="firstHeading">%user</h2><div>%text</div><div><a href="%url" target="_blank">%url</a></div><div>Date Posted- %date</div></div>';
templates[1] = '<table width="320" border="0"><tr><td class="user" colspan="2">%user</td></tr><tr><td width="45"><a href="%profile_img"><img src="%profile_img" width="55" height="50"/></a></td><td width="186">%text<p><a href="%url" target="_blank">%url</a></p></td></tr></table><hr/>';
templates[3] = "https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=false&screen_name=%val&count=10&callback=?";
$$ = { //cache of jQuery objects
news_tweets: $("#news-tweets"),
user_banner: $('#user-banner')
};
// *** functions ***
function news_tweets(value1) {
$$.news_tweets.empty();
var bounds = new google.maps.LatLngBounds(); //??
var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
$.getJSON(templates[3].replace('%val', value1), function(data) {
var d, len = data.length;
for (var i = 0; i < len; i++) {
var item = data[i];
d = {
text: item.text,
user : item.user.name,
date: item.created_at,
profile_img: item.user.profile_image_url,
url: (item.entities && item.entities.urls && item.entities.urls.length) ? item.entities.urls[0].url : '',
locale: null
}
d.$tweet = $(templates[1].replace('%user', d.user).replace(/%profile_img/g, d.profile_img).replace('%text', d.text).replace(/%url/g, d.url))
.appendTo($$.news_tweets.css("overflow", "scroll"))
.find(".user")
.Placemaker('getPlaces', d) //.Placemaker('getPlaces') returns a promise
.done(function(o, d) {
var m = ($.isArray(o.match) ? o.match[0] : o.match) || {};
if(m.place) {
var myLatLng = new google.maps.LatLng(m.place.centroid.latitude, m.place.centroid.longitude);
var marker = new google.maps.Marker({
icon: d.profile_img,
title: d.user,
map: map,
position: myLatLng
});
var infowindow = new google.maps.InfoWindow({
content: templates[0].replace('%user', d.user).replace('%text', d.text).replace(/%url/g, d.url).replace('%date', d.date)
});
function openInfoWindow() {
infowindow.open(map, marker);
}
google.maps.event.addListener(marker, 'click', openInfoWindow);
this.each(function() { //`this` is already a jQuery object. Re-wrapping as `$(this)` is not necessary.
$(this).on('click', openInfoWindow).css({'color':'#900', 'text-decoration':'underline', 'cursor':'pointer'});//$(this) is an individual tweet in #news_tweets.
});
bounds.extend(myLatLng); //??
}
}).fail(function(err) {
console.log(err.message);
});
}
});
}
// *** event handlers ***
$("#newsTypes").on('click', 'img', function() {
news_tweets($(this).data('type'));
//user_tweets("euronews");
});
});
これの中心には、次の構造があります。
for(...) {
var d = {...}; //object map comprising both data and options
$(htmlString).appendTo(...).find(...).Placemaker('getPlaces', d).done(fn{}).fail(fn{});
}
次のことに注意することが重要です。
- jQuery メソッド チェーンは、標準の jQuery オブジェクトから始まります。
- from
.Placemaker('getPlaces', d)
、チェーン内のメソッドは jQuery promise オブジェクトを返します。
.done()
と.fail()
ハンドラーの両方でthis
、元の標準 jQuery オブジェクトと同等です。
- 式の 2 番目の引数として渡されたデータ マップは、ハンドラー
.Placemaker('getPlaces', d)
の 2 番目の引数として再表示されます。.done()
この機能により.Placemaker('getPlaces', d)
、具体的にデータをクロージャーに入れたり、.data()
. この点で、「getPlaces」メソッドはクロージャーとして効果的に機能するだけでなく、必要な非同期ルックアップ動作を提供します。
これはすべて、あなたの視点に応じて、完全に混乱していると判断されるか、完全に賢いと判断されます.