// ==UserScript==
// @name Fuck-Yudao
// @namespace none
// @version 0.4
// @license MIT
// @description Help you climb over the paywall for a so-called "Free & Open Source Software", built by someone who truly understand our generations duty. To you-know-who: *thank you*. China's OSS environment got much better because of professionals like you.
// @author The love you care
// @match https://www.iocoder.cn/*
// @match https://doc.iocoder.cn/*
// @match https://cloud.iocoder.cn/*
// @grant unsafeWindow
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// Overwrite jqueryAlert, simply comment out `init` can disable the annoying dialog
unsafeWindow.jqueryAlert = function(opts) {
var opt = {
'style': 'wap',
'title': '',
'content': '',
'contentTextAlign': 'center',
'width': 'auto',
'height': 'auto',
'minWidth': '0',
"className": '',
'position': 'fixed',
'animateType': 'scale',
'modal': false,
'isModalClose': false,
'bodyScroll': false,
'closeTime': 3000,
"buttons": {},
}
var option = $.extend({}, opt, opts);
var dialog = {}
dialog.time = 0;
dialog.init = function() {
dialog.framework();
}
var isHaveTouch = "ontouchend"in document ? true : false;
if (isHaveTouch) {
dialog.event = 'touchstart';
} else {
dialog.event = 'click';
}
var $modal = $("<div class='alert-modal'>")
var $container = $("<div class='alert-container animated'>");
var $title = $("<div class='alert-title'>" + option.title + "</div>");
var $content = $("<div class='alert-content'>");
var $buttonBox = $("<div class='alert-btn-box'>");
var $closeBtn = $("<div class='alert-btn-close'>×</div>");
if (option.content[0].nodeType == 1) {
var $newContent = option.content.clone();
$content.append($newContent)
} else {
$content.html(option.content);
}
dialog.framework = function() {
dialog.buttons = [];
for (var key in option.buttons) {
dialog.buttons.push(key);
}
dialog.buttonsLength = dialog.buttons.length;
$container.append($title).append($content);
if (option.style == 'pc') {
$container.append($closeBtn).addClass('pcAlert');
}
if (option.modal || option.modal == 'true') {
$('body').append($modal)
option.bodyScroll && $('body').css('overflow', 'hidden');
}
$('body').append($container)
$content.css({
'text-align': option.contentTextAlign
})
if (parseInt(option.minWidth) > parseInt($container.css('width'))) {
option.width = option.minWidth;
}
$modal.css('position', option.position);
$modal.css('z-index', zIndex);
++zIndex;
if (option.position == 'fixed') {
$container.css({
'position': option.position,
'left': '50%',
'top': '50%',
'z-index': zIndex,
})
}
if (option.position == 'absolute') {
$container.css({
'position': option.position,
'left': $(window).width() / 2,
'top': $(window).height() / 2 + $(window).scrollTop(),
'z-index': zIndex,
})
}
$container.css('width', option.width);
$container.css('height', option.height);
if (option.width == 'auto') {
$container.css('width', $container[0].clientWidth + 10);
}
if (parseInt($(window).height()) <= parseInt($container.css('height'))) {
$container.css('height', $(window).height());
}
(!!option.className) && $container.addClass(option.className);
for (var key in option.buttons) {
var $button = $("<p class='alert-btn-p'>" + key + "</p>");
if (option.style != 'pc') {
$button.css({
'width': Math.floor(($container[0].clientWidth) / dialog.buttonsLength),
})
}
$button.bind(dialog.event, option.buttons[key]);
$buttonBox.append($button);
}
if (dialog.buttonsLength > 0) {
$container.append($buttonBox);
$content.css('padding-bottom', '46px');
}
if (option.title != '') {
$content.css('padding-top', '42px');
}
if (dialog.buttonsLength <= 0 && option.title == '') {
$container.addClass('alert-container-black');
}
$container.css({
'margin-left': -parseInt($container.css('width')) / 2,
'margin-top': -parseInt($container.css('height')) / 2,
});
if (option.animateType == 'scale') {
$container.addClass('bounceIn');
}
if (option.animateType == 'linear') {
$container.addClass('linearTop');
}
isSelfClose();
}
;
function isSelfClose() {
if (dialog.buttonsLength <= 0 && option.style != 'pc') {
setTimeout(function() {
$container.fadeOut(300);
$modal.fadeOut(300);
option.bodyScroll && $('body').css('overflow', 'auto');
}, option.closeTime)
}
}
dialog.toggleAnimate = function() {
if (option.animateType == 'scale') {
return $container.removeClass('bounceIn').addClass('bounceOut');
} else if (option.animateType == 'linear') {
return $container.removeClass('linearTop').addClass('linearBottom');
} else {
return $container;
}
}
dialog.close = function() {
dialog.toggleAnimate().fadeOut(dialog.time);
$modal.fadeOut(dialog.time);
option.bodyScroll && $('body').css('overflow', 'auto');
}
;
option.style == 'pc' && $closeBtn.bind(dialog.event, dialog.close);
option.isModalClose && $modal.bind(dialog.event, dialog.close);
dialog.destroy = function() {
dialog.toggleAnimate().fadeOut(dialog.time);
setTimeout(function() {
$container.remove();
$modal.remove();
option.bodyScroll && $('body').css('overflow', 'auto');
}, dialog.time)
}
dialog.show = function() {
}
// dialog.init();
dialog.close();
return dialog;
}
// The content of yudao's pooly-written documentation. Almost at the same miserable level as uni-app's docs.
// Read the docs of vue, react and a lot more responsible, real open source repos to learn how to make professional statements.
let yudaosPoorlyWrittenDoc = null, prevPath = document.location.pathname;
// The routes that are currently being marked as VIP only. Real jokes.
const blockPathList = ['bpm', 'user-center', 'social-user', 'oauth2', 'saas-tenant', 'sms', 'mail', 'notify', 'mybatis-pro', 'dynamic-datasource', 'report', 'Spring-Boot', 'Spring-Cloud', 'api-doc', 'module-new', 'new-feature', 'dev-hot-swap', 'file', 'message-queue', 'job', 'idempotent', 'distributed-lock', 'rate-limiter', 'project-rename', 'delete-code', 'resource-permission', 'data-permission', 'deployment-linux', 'deployment-docker', 'mp', 'mall', 'pay', 'crm', 'member', 'erp', 'websocket', 'vo', 'system-log', 'ai', 'cloud-debug', 'registry-center', 'config-center', 'gateway', 'rpc', 'distributed-transaction', 'server-protection'];
// If the current url is 'blocked'.
// You do know that for a static documentation site nothing is really blocked, don't you
const isBlocked = () => {
const ret = blockPathList.some((e) => document.location.pathname.includes(e));
return ret;
}
// Get the documentation content wrapper element
const getWrapper = () => {
return document.querySelector('.content-wrapper');
}
const replace = (str) => {
const wrapper = getWrapper()
if (str) {
while (wrapper.innerHTML !== str) {
wrapper.innerHTML = str
}
}
}
const contentObserver = new MutationObserver(() => {
if (getWrapper().innerHTML.includes('仅 VIP 可见')) {
replace(yudaosPoorlyWrittenDoc)
}
})
const urlObserver = new MutationObserver(() => {
const wrapperEl = getWrapper()
/*
if (document.location.href !== 'https://doc.iocoder.cn/' && isBlocked() && !window.location.href.includes('refreshed')) {
window.location.href = window.location.href + '?refreshed=1'
// window.location.reload();
}
*/
if (prevPath !== document.location.pathname) {
window.location.reload()
}
})
urlObserver.observe(document.body, { childList: true })
//=============================================================================================================================================
const $$wrapper = getWrapper();
if (getWrapper() && isBlocked()) {
yudaosPoorlyWrittenDoc = $$wrapper.innerHTML.includes('仅 VIP 可见') ? null : $$wrapper.innerHTML;
unsafeWindow.$$content = yudaosPoorlyWrittenDoc;
unsafeWindow.$$replace = function() {
replace(unsafeWindow.$$content)
}
contentObserver.observe($$wrapper, { childList: true, characterData: true, subtree: true });
replace(yudaosPoorlyWrittenDoc);
}
//=============================================================================================================================================
})();