Created
April 26, 2013 11:55
-
-
Save XP1/5466945 to your computer and use it in GitHub Desktop.
Fix Yahoo! comments: Fixes Yahoo! comments in Opera 12.1x by constructing a multipart response manually.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Fix Yahoo! comments | |
// @version 1.00 | |
// @description Fixes Yahoo! comments in Opera 12.1x by constructing a multipart response manually. | |
// @namespace https://gist.github.com/XP1/5466945/ | |
// @copyright 2013 | |
// @author XP1 | |
// @homepage https://github.com/XP1/ | |
// @license Apache License, Version 2.0; http://www.apache.org/licenses/LICENSE-2.0 | |
// @include http*://news.yahoo.*/* | |
// @include http*://*.news.yahoo.*/* | |
// ==/UserScript== | |
/* | |
* Copyright 2013 XP1 | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
/*jslint browser: true, vars: true, maxerr: 50, indent: 4 */ | |
(function (window, Object, XMLHttpRequest) { | |
"use strict"; | |
var before = function before(searchValue, fromIndex) { | |
return (this.substring(0, this.indexOf(searchValue, fromIndex))); | |
}; | |
var beforeInclusive = function beforeInclusive(searchValue, fromIndex) { | |
return (this.substring(0, this.indexOf(searchValue, fromIndex) + searchValue.length)); | |
}; | |
var after = function after(searchValue, fromIndex) { | |
return (this.substring(this.indexOf(searchValue, fromIndex) + searchValue.length)); | |
}; | |
function getPairs(uri) { | |
return after.call(uri, "?").split("&"); | |
} | |
function containsMultipart(uri) { | |
return (getPairs(uri).indexOf("m_mode=multipart") !== -1); | |
} | |
function getFragmentUri(uri) { | |
var change = { | |
m_mode: "fragment", | |
y_map_urn: null, | |
_sig: null | |
}; | |
var pairs = getPairs(uri); | |
var fragmentPairs = []; | |
var i = null; | |
var length = pairs.length; | |
for (i = 0; i < length; i += 1) { | |
var singletons = pairs[i].split("="); | |
var name = singletons[0]; | |
var value = singletons[1]; | |
var changeValue = change[name]; | |
var isExclusion = (changeValue === null); | |
if (!isExclusion) { | |
var needsChange = change.hasOwnProperty(name); | |
fragmentPairs.push(name + "=" + (needsChange ? encodeURIComponent(changeValue) : value)); | |
} | |
} | |
return (beforeInclusive.call(uri, "?") + fragmentPairs.join("&")); | |
} | |
function constructMultipartResponse(request) { | |
var response = []; | |
// For each part, there is a split separator that looks like "--dali-response-split". | |
// It should match the regex `/^--dali-response-split(?:-[a-z0-9]+)?/gm`. | |
// Construct the text parts. | |
var blob = request.getResponseHeader("X-Maple-Embed-Blob"); | |
var parts = blob.split(/,\s*/g); | |
var p = null; | |
var numberOfParts = parts.length; | |
for (p = 0; p < numberOfParts; p += 1) { | |
var sections = parts[p].split(/;\s*/g); | |
var numberOfSections = sections.length; | |
if (numberOfSections >= 2) { | |
var header = sections[0].trim(); | |
response.push(""); | |
response.push("--dali-response-split"); | |
response.push("Content-Type: text/plain; charset=utf-8"); | |
response.push("RMP-Embed-Location: " + after.call(header, "location=")); | |
var s = null; | |
for (s = 1; s < numberOfSections; s += 1) { | |
var body = decodeURIComponent(sections[s].trim().replace(/\+/g, " ")); | |
response.push(""); | |
response.push(body); | |
} | |
} | |
} | |
// Construct the HTML part. | |
response.push(""); | |
response.push("--dali-response-split"); | |
response.push("Content-Type: text/html; charset=utf-8"); | |
response.push(""); | |
response.push(request.responseText); | |
// End multipart response. | |
response.push("--dali-response-split"); | |
response.push(""); | |
return response.join("\r\n"); | |
} | |
function handleMultipartRequests() { | |
var XMLHttpRequestPrototype = XMLHttpRequest.prototype; | |
function logMultipartRequests() { | |
var realOpen = XMLHttpRequestPrototype.open; | |
XMLHttpRequestPrototype.open = function open(method, url, async, user, password) { | |
var isMultipart = containsMultipart(url); | |
if (isMultipart) { | |
if (!this.hasOwnProperty("storage")) { | |
Object.defineProperty(this, "storage", {value: {}}); | |
} | |
var storage = this.storage; | |
// Add propositions. | |
if (!storage.hasOwnProperty("proposition")) { | |
storage.proposition = {}; | |
} | |
storage.proposition.isMultipart = isMultipart; | |
// Add parameters. | |
if (!storage.hasOwnProperty("parameter")) { | |
storage.parameter = {}; | |
} | |
var parameter = storage.parameter; | |
if (!parameter.hasOwnProperty("open")) { | |
parameter.open = {}; | |
} | |
parameter.open.method = method; | |
parameter.open.url = url; | |
parameter.open.async = async; | |
parameter.open.user = user; | |
parameter.open.password = password; | |
} | |
return realOpen.call(this, method, url, async, user, password); | |
}; | |
} | |
function replaceMultipartRequests() { | |
var realSend = XMLHttpRequestPrototype.send; | |
XMLHttpRequestPrototype.send = function send(data) { | |
var storage = this.storage; | |
var isMultipart = (this.hasOwnProperty("storage") && storage.proposition.isMultipart); | |
if (!isMultipart) { | |
return realSend.call(this, data); | |
} | |
var openParameter = storage.parameter.open; | |
var request = new XMLHttpRequest(); | |
request.open(openParameter.method, getFragmentUri(openParameter.url), false, openParameter.user, openParameter.password); | |
var fragmentResult = realSend.call(request, data); | |
realSend.call(this, data); // Send the multipart request to trigger status and event changes. | |
// Construct multipart response. | |
var multipartResponse = constructMultipartResponse(request); | |
Object.defineProperties(this, { | |
response: {value: multipartResponse}, | |
responseText: {value: multipartResponse} | |
}); | |
return fragmentResult; | |
}; | |
} | |
logMultipartRequests(); | |
replaceMultipartRequests(); | |
} | |
handleMultipartRequests(); | |
}(this, this.Object, this.XMLHttpRequest)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I posted this user JS in this thread:
can't see yahoo comments:
http://my.opera.com/community/forums/topic.dml?id=1640352