(function(){ var defaultSettings = { prefetchNext: 5, //number of prefetched pages ahead prefetchBack: 5, //number of prefetched pages behind prefetchNextStart: 2, //number of prefetched pages ahead when the script starts prefetchBackStart: 1, //number of prefetched pages behind when the script starts prefetchNoNext: true, //specifies if previous page should be prefetched when theres no next page fullLayout: true, //true for full layout mode, false for minimalistic mode clickImgNavigates: true, //specifies if clicking the image will change pages clikLeftHalfGoesBack: true, //specifies if clicking the left half of the image will take you to the previous page flipControlsManga: false, //flip the controls (L/R arrows, L/R image click, back/next buttons) for mangas or other right-to-left content autozoom: false, //enable fit-to-screen shrinkWidth: false, //when fit-to-screen enabled and image too wide, shrink it shrinkHeight: false, //when fit-to-screen enabled and image too long, shrink it expandWidth: false, //when fit-to-screen enabled and image too narrow, expand it expandHeight: false, //when fit-to-screen enabled and image too short, expand it showButtons: true, //show or hide the buttons (back/next, bookmarks, settings, etc...) borderLR: 0, //pixels to leave as border to the sides of the image when zooming and scrolling borderUD: 0, //pixels to leave as border above and below the image when zooming and scrolling goToBookmark: true, //if you have 1 bookmark saved for a site, asks you if you want to go there when you visit the site moveWhileLoading: false, //lets you change pages even if the image for the next page is still loading debugMode: false, //alerts on errors, and shows some of the currently cache'd pages/images with the "," key showSettingsOnFail: false, //if no settings are found for this site and default ones didn't work, show settings screen keyboardShortcuts: { //keyboard shortcuts... back: {name: 'LEFT', keyCode: 37, ctrlKey: false, shiftKey: false, altKey: false}, next: {name: 'RIGHT', keyCode: 39, ctrlKey: false, shiftKey: false, altKey: false}, scroll_left: {name: 'CTRL + LEFT', keyCode: 37, ctrlKey: true, shiftKey: false, altKey: false}, scroll_right: {name: 'CTRL + RIGHT', keyCode: 39, ctrlKey: true, shiftKey: false, altKey: false}, scroll_up: {name: 'CTRL + UP', keyCode: 38, ctrlKey: true, shiftKey: false, altKey: false}, scroll_down: {name: 'CTRL + DOWN', keyCode: 40, ctrlKey: true, shiftKey: false, altKey: false}, reload: {name: '.', keyCode: 190, ctrlKey: false, shiftKey: false, altKey: false}, set_bm: {name: 'CTRL + ALT + B', keyCode: 66, ctrlKey: true, shiftKey: false, altKey: true}, add_bm: {name: 'CTRL + ALT + A', keyCode: 65, ctrlKey: true, shiftKey: false, altKey: true}, layout: {name: '-', keyCode: isWebKit() ? 189 : 173, ctrlKey: false, shiftKey: false, altKey: false}, botones: {name: 'SHIFT + -', keyCode: isWebKit() ? 189 : 173, ctrlKey: false, shiftKey: true, altKey: false}, fit: {name: '+', keyCode: isWebKit() ? 187 : 171, ctrlKey: false, shiftKey: false, altKey: false}, slide: {name: 'CTRL + ALT + S', keyCode: 83, ctrlKey: true, shiftKey: false, altKey: true}, debug_mode: {name: 'CTRL + ALT + X', keyCode: 88, ctrlKey: true, shiftKey: false, altKey: true}, debug_info: {name: ',', keyCode: 188, ctrlKey: false, shiftKey: false, altKey: false} } }; // ==UserScript== // @name Webcomic Reader // @author Javier Lopez https://github.com/ameboide , fork by v4Lo https://github.com/v4Lo and by anka-213 http://github.com/anka-213 // @version 2019.09.12 // @license MIT // @namespace http://userscripts.org/scripts/show/59842 // @description Can work on almost any webcomic/manga page, preloads 5 or more pages ahead (or behind), navigates via ajax for instant-page-change, lets you use the keyboard, remembers your progress, and it's relatively easy to add new sites // @homepageURL https://github.com/anka-213/webcomic_reader#readme // @supportURL https://github.com/anka-213/webcomic_reader/issues // @updateURL https://raw.githubusercontent.com/anka-213/webcomic_reader/master/webcomic_reader.user.js // @updatetype 24 // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_openInTab // @include http://www.sluggy.com/* // @include http://sluggy.com/* // @include http://www.penny-arcade.com/comic* // @include http://penny-arcade.com/comic* // @include https://www.penny-arcade.com/comic* // @include https://penny-arcade.com/comic* // @match *://*.xkcd.com/* // @include http://www.giantitp.com/* // @include http://www.dilbert.com/strip/* // @include http://dilbert.com/strip/* // @include http://hf.dilbert.com/strip/* // @include http://www.explosm.net/* // @include http://explosm.net/* // @include http://www.nuklearpower.com/* // @include http://www.reallifecomics.com/* // @include http://reallifecomics.com/* // @include http://www.pvponline.com/* // @include http://pvponline.com/* // @include http://www.brawlinthefamily.com/* // @include http://drmcninja.com/* // @include http://www.vgcats.com/*/* // @include http://www.phdcomics.com/* // @include http://www.cad-comic.com/* // @match *://*.smbc-comics.com/* // @include http://abstrusegoose.com/* // @include http://thedoghousediaries.com/* // @include http://www.erfworld.com/* // @include http://es.juanelo.net/*/* // @include http*://readms.net/* // @include http*://*.readms.net/* // @include http://www.qwantz.com/* // @include http://qwantz.com/* // @include http://www.2pstart.com/*/* // @include http://www.spaceavalanche.com/* // @include http://www.gunshowcomic.com/* // @include http://gunshowcomic.com/* // @include http://www.terrorisland.net/* // @include http://nedroid.com/* // @include http://www.bobandgeorge.com/* // @include http://bobandgeorge.com/* // @include http://www.stationv3.com/* // @include http://www.lfgcomic.com/page/* // @include http://lfgcomic.com/page/* // @include http://www.gpf-comics.com/* // @match *://*.questionablecontent.net/* // @include http://www.daisyowl.com/* // @include http://daisyowl.com/* // @include http://www.hyperdeathbabies.com/* // @include http://amultiverse.com/* // @include http://wondermark.com/* // @include http://www.amazingsuperpowers.com/* // @match *://fanfox.net/* // @match *://m.fanfox.net/* // @include http://www.leasticoulddo.com/* // @include http://leasticoulddo.com/* // @include http://www.sinfest.net/* // @include http://www.crfh.net/* // @include http://crfh.net/* // @include http://www.pennyandaggie.com/* // @include http://pennyandaggie.com/* // @include http://www.darkbolt.com/* // @include http://darkbolt.com/* // @match *://egscomics.com/* // @match *://www.egscomics.com/* // @include http://www.the-gutters.com/* // @include http://noneedforbushido.com/* // @include http://www.teahousecomic.com/* // @include http://www.applegeeks.com/* // @include http://applegeeks.com/* // @include http://www.nettserier.no/* // @include http://nettserier.no/* // @include http*://www.nerfnow.com/* // @include http://www.little-gamers.com/* // @include http://www.duelinganalogs.com/* // @include http://www.myextralife.com/* // @include http://notinventedhe.re/* // @include *://mangaseeonline.us/* // @include http://www.unshelved.com/* // @include https://www.eviscerati.org/comics* // @include http://buttersafe.com/* // @include http://www.romanticallyapocalyptic.com/* // @include http://romanticallyapocalyptic.com/* // @include http://www.somethingpositive.net/* // @include http://somethingpositive.net/* // @include http://www.rhymes-with-witch.com/* // @include http://rhymes-with-witch.com/* // @include http://www.superstupor.com/* // @include http://superstupor.com/* // @include http://www.misfile.com/* // @include http://www.asofterworld.com/* // @include http://asofterworld.com/* // @include http://www.achewood.com/* // @include http://achewood.com/* // @include http://www.biggercheese.com/* // @include http://biggercheese.com/* // @include http://www.gwscomic.com/* // @include http://gwscomic.com/* // @include http://www.fonflatter.de/* // @include http://www.ruthe.de/* // @include http://ruthe.de/* // @include http://www.daybydaycartoon.com/* // @include http://daybydaycartoon.com/* // @include http://www.dieselsweeties.com/* // @include http://dieselsweeties.com/* // @include http://www.foxtrot.com/* // @include http://www.csectioncomics.com/* // @include http://garfieldminusgarfield.net/* // @include http://www.girlgeniusonline.com/* // @include http://www.gocomics.com/* // @exclude http://www.gocomics.com/ // @exclude http://www.gocomics.com/?* // @include http*://www.gunnerkrigg.com/* // @include http*://gunnerkrigg.com/* // @include http://www.ho-lo.co.il/* // @include http://www.threepanelsoul.com/* // @include http://threepanelsoul.com/* // @match *://*.oglaf.com/* // @include http://www.kevinandkell.com/* // @include http://kevinandkell.com/* // @include http://www.lackadaisycats.com/comic.php* // @include http://lackadaisycats.com/comic.php* // @include http://www.lukesurl.com/* // @include http://mycardboardlife.com/* // @include http*://megatokyo.com/* // @include http*://www.megatokyo.it/* // @include http*://www.megatokyo.de/* // @include http://noreasoncomics.com/* // @include http://www.pixelcomic.net/* // @include http://pixelcomic.net/* // @include http://www.redmeat.com/* // @include http://redmeat.com/* // @include http://sexylosers.com/* // @include http://www.doonesbury.com/* // @include http://www.pbfcomics.com/* // @include http://tjandamal.com/* // @include http://sfeertheory.littlefoolery.com/* // @include http://wanderingones.com/* // @include http://www.big-big-truck.com/ayiw/* // @include http://big-big-truck.com/ayiw/* // @include http://wapsisquare.com/* // @include http://www.wastedtalent.ca/* // @include http://www.wulffmorgenthaler.com/* // @include http://wulffmorgenthaler.com/* // @include http://www.weregeek.com/* // @include http://*.katbox.net/* // @include http://*.keenspace.com/* // @include http://*.comicgenesis.com/* // @include http://www.beanleafpress.com/* // @include http://www.theoswaldchronicles.com/* // @include *://www.awkwardzombie.com/* // @include *://awkwardzombie.com/* // @include http://*.seraph-inn.com/* // @include https://www.fakku.net/manga/* // @include https://www.fakku.net/doujinshi/* // @include http://www.deadwinter.cc/* // @include http://deadwinter.cc/* // @include http://www.loveisintheblood.com/* // @include http://rhapsodies.wpmorse.com/* // @include http://www.piratesofmars.com/* // @include http://www.earthsongsaga.com/vol* // @include http://www.goblinscomic.org/* // @include http://www.venusenvycomic.com/* // @include http://venusenvycomic.com/* // @include http://www.meekcomic.com/* // @include http://www.dominic-deegan.com/* // @include http://dominic-deegan.com/* // @include http://yafgc.net/* // @include http://www.sdamned.com/* // @include http://www.twolumps.net/* // @include http://twolumps.net/* // @include http://www.precociouscomic.com/* // @include http://precociouscomic.com/* // @include http://betweenplaces.spiderforest.com/* // @include http://specialschool.spiderforest.com/* // @include http://requiem.spiderforest.com/* // @include http://sevensmith.net/chirault/* // @include http://www.junglestudio.com/roza/* // @include http://www.dream-scar.net/* // @include http://dream-scar.net/* // @include http://www.tryinghuman.com/* // @include http://tryinghuman.com/* // @include http://www.thedreamercomic.com/* // @include http://thedreamercomic.com/ // @include http://www.shazzbaa.com/* // @include http://shazzbaa.com/* // @match *://*.sandraandwoo.com/* // @include http://www.freakangels.com/* // @include http://www.sakanacomic.com/* // @include http://keychain.patternspider.net/* // @include http://www.collectedcurios.com/* // @include http://www.sylvanmigdal.com/* // @include http://sylvanmigdal.com/* // @include http://www.c.urvy.org/* // @include http://c.urvy.org/* // @include http://www.doublefine.com/* // @include http://www.survivingtheworld.net/* // @include http://survivingtheworld.net/* // @include http://nonadventures.com/* // @include http://www.robandelliot.cycomics.com/* // @include http://robandelliot.cycomics.com/* // @include http://soulsymphonycomic.com/* // @include http://www.blastwave-comic.com/* // @include http://www.channelate.com/* // @include http://www.optipess.com/* // @include http://www.drawuntilitsfunny.com/* // @include http://beardfluff.com/* // @include http://lawlscomic.com/* // @include http://www.maakies.com/* // @include http://www.lefthandedtoons.com/* // @include http://trollscience.com/* // @include http://www.diggercomic.com/* // @include http://luciphurrsimps.com/* // @include http://nikkisprite.com/* // @include http://www.gronkcomic.com/* // @include http://www.redsplanet.com/* // @include http://www.cowshell.com/* // @include http://everblue-comic.com/* // @include http://tmkcomic.depleti.com/* // @include http://www.remindblog.com/* // @include http://inkdolls.com/* // @include http://www.terra-comic.com/* // @include http://www.redmoonrising.org/* // @include http://www.khaoskomix.com/* // @include http://memoria.valice.net/* // @include http://www.twilightlady.com/* // @include http*://e-hentai.org/* // @include http://www.perveden.com/* // @include http://www.bittersweetcandybowl.com/* // @include http://www.imagebam.com/* // @include http://www.exploitationnow.com/* // @include http://basicinstructions.net/* // @include http://www.missmab.com/* // @include http://www.lookwhatibroughthome.com/* // @include http://hijinksensue.com/* // @include http://www.darthsanddroids.net/* // @include http://darthsanddroids.net/* // @include http://www.harkavagrant.com/* // @include http://dresdencodak.com/* // @include http://www.straysonline.com/comic/* // @include http://straysonline.com/comic/* // @include http://www.dragonball-multiverse.com/* // @include http://insanesoft.org/fanfyria/* // @include http://*.snafu-comics.com/* // @include http://www.wayfarersmoon.com/* // @include http://wayfarersmoon.com/* // @include http://*.smackjeeves.com/* // @include http://www.10kcommotion.com/* // @include http://10kcommotion.com/* // @include http://www.multiplexcomic.com/* // @include http://multiplexcomic.com/* // @include http://www.johnandjohn.nl/index.php?*wltypeid=1* // @include http://www.sorcery101.net/* // @include http://www.treadingground.com/* // @include http://www.kiwiblitz.com/* // @include http://thepunchlineismachismo.com/* // @include http://kafkaskoffee.com/* // @include http://occasionalcomics.com/* // @include http://www.zombieboycomics.com/* // @include http://www.babyblues.com/* // @include http://babyblues.com/* // @include http://www.bearandtiger.com/* // @include http*://exhentai.org/* // @include http://www.wigucomics.com/* // @include http://www.mankin-trad.net/* // @include http://mankin-trad.net/* // @include http://www.scarygoround.com/* // @include http://scarygoround.com/* // @include http://www.schlockmercenary.com/* // @include http://www.warehousecomic.com/* // @include http://warehousecomic.com/* // @include http://www.tnemrot.com/* // @include http://www.holiday-wars.com/* // @include http://www.zapcomic.com/* // @include http://www.dumbingofage.com/* // @include http://www.shortpacked.com/* // @include http://www.itswalky.com/* // @include http://itswalky.com/* // @include http://www.evildivacomics.com/* // @include http://axecop.com/* // @include http://www.reddit.com/ // @include http://www.reddit.com/?* // @include http://www.reddit.com/r/* // @exclude http://www.reddit.com/*/comments/* // @include http://blankitcomics.com/* // @include http://doctorcatmd.com/* // @include http://www.sheldoncomics.com/* // @include http://sheldoncomics.com/* // @include http://luscious.net/*/pictures/* // @include http://www.geekculture.com/joyoftech/* // @include http://www.realmofatland.com/* // @include http://realmofatland.com/* // @include http://thedoujin.com/index.php/pages/* // @include http://www.oslevadosdabreca.com/* // @include http://www.thedevilbear.com/* // @include http://thedevilbear.com/* // @include http://www.exiern.com/* // @include http://nsfw-comix.com/* // @include http://jaynaylor.com/* // @include http://www.anelnoath.com/* // @include http://www.faans.com/* // @include http://www.truefork.org/* // @include http://truefork.org/* // @include http*://www.thewotch.com/* // @include http*://cheer.sailorsun.org/* // @include http://montrose.is/sgvy/archives/* // @include http://www.montrose.is/sgvy/archives/* // @include http://www.drunkduck.com/* // @include http://drunkduck.com/* // @include http://www.ephralon.de/seekers_detailed.php* // @include http://ephralon.de/seekers_detailed.php* // @include http://www.terinu.com/* // @include http://terinu.com/* // @include http://dcisgoingtohell.com/* // @include http://las-historietas.blogspot.com/* // @include http://www.palcomix.com/* // @include http://palcomix.com/* // @include http://malandchad.com/* // @include http://www.digitalcomicmuseum.com/* // @include http://digitalcomicmuseum.com/* // @include http://fourcolorshadows.blogspot.com/* // @include http://thehorrorsofitall.blogspot.com/* // @include *//bato.to/chapter* // @include http://www.octopuspie.com/* // @include http://www.lovemenicecomic.com/* // @include http://blog.saveapathea.com/* // @include http://www.dead-philosophers.com/* // @include http://www.kingfeatures.com/* // @include http://kingfeatures.com/* // @include http://www.thezombiehunters.com/* // @include http://thezombiehunters.com/* // @include http://www.bugcomic.com/* // @include http://www.interrobangstudios.com/* // @include http://interrobangstudios.com/* // @include http://syacartoonist.com/* // @include http://satwcomic.com/* // @include http://stupidfox.net/* // @include http://www.casualvillain.com/* // @include http://fanboys-online.com/* // @include http://www.girlswithslingshots.com/* // @include http://www.mntgaiden.com/* // @include http://ravensdojo.com/* // @include http://freefall.purrsia.com/* // @include http://www.shd-wk.com/* // @include http://shd-wk.com/* // @include http://www.pepsaga.com/* // @include http://slimythief.com/* // @include http://www.pebbleversion.com/* // @include http://pebbleversion.com/* // @include http://www.accurseddragon.com/* // @include http://www.stringtheorycomic.com/* // @include http://www.supercrash.net/* // @include http://loveandcapes.com/* // @include http://victorycomic.comicgenesis.com/* // @include http://magellanverse.com/* // @include http://www.evil-comic.com/* // @include http://flakypastry.runningwithpencils.com/* // @include http://www.pointguardian.com/* // @include http://gogetaroomie.chloe-art.com/* // @include http://www.amazingagentjennifer.com/* // @include http://mindmistress.comicgenesis.com/* // @include http://www.evernightcomic.com/* // @include http://*.thewebcomic.com/* // @include http://www.comicstriplibrary.org/display/* // @include http://comicstriplibrary.org/display/* // @include http://www.ourmanga.com/* // @include http://read.egscans.com/* // @include http://*.tiraecol.net/* // @include http://tiraecol.net/* // @include http://www.conejofrustrado.com/* // @include http://www.e2w-illustration.com/* // @include http://comic.naver.com/* // @include http://www.peteristhewolf.com/* // @include http://peteristhewolf.com/* // @include http://www.wlpcomics.com/* // @include http://wlpcomics.com/* // @include http://trenchescomic.com/* // @include http://www.goominet.com/unspeakable-vault/* // @include http://www.doesnotplaywellwithothers.com/* // @include http://www.aikoniacomic.com/* // @include http://aikoniacomic.com/* // @include http*://grrlpowercomic.com/* // @include http://www.poisonedminds.com/* // @include http://poisonedminds.com/* // @include http://nodwick.humor.gamespy.com/* // @include http://www.the-whiteboard.com/* // @include http://the-whiteboard.com/* // @include http://www.mezzacotta.net/* // @include http://www.hbrowse.com/* // @include http://www.bardsworth.com/* // @include http://fancyadventures.com/* // @include http://www.purplepussy.net/* // @include http://purplepussy.net/* // @include http://www.darklegacycomics.com/* // @include http://darklegacycomics.com/* // @include http://candicomics.com/* // @include http://www.buckocomic.com/* // @include http://bearmageddon.com/* // @include http://betweenfailures.net/* // @include http://www.sisterclaire.com/* // @include http://www.awesomehospital.com/* // @include http://ars.userfriendly.org/cartoons/* // @include http://www.friendswithboys.com/* // @include http://www.jesusandmo.net/* // @include http://www.calamitiesofnature.com/* // @include http://www.rosalarian.com/* // @include http://rosalarian.com/* // @include http://www.irregularwebcomic.net/* // @include http://adistantsoil.com/* // @include http://comic.nodwick.com/* // @include http://ffn.nodwick.com/* // @include http://ps238.nodwick.com/* // @include http://thedevilspanties.com/* // @include http://www.animephile.com/* // @match *://kissmanga.com/* // @include http://invisiblebread.com/* // @include http://www.vickifox.com/* // @include http://www.spinnyverse.com/* // @include http://zenpencils.com/* // @include http://webcomics.yaoi911.com/* // @include http://www.whompcomic.com/* // @include http://curtailedcomic.com/* // @include http://bradcolbow.com/* // @include http://www.theherobiz.com/* // @include http://guildedage.net/* // @include http://betweenfailures.com/* // @include http://www.claudeandmonet.com/* // @include http://de.ninemanga.com/* // @include http://www.bloomingfaeries.com/* // @include http://www.findchaos.com/* // @include http://chaoslife.findchaos.com/* // @include http://www.shadbase.com/* // @include http://www.shagbase.com/* // @include http://www.mrlovenstein.com/* // @include http://www.anticscomic.com/* // @include http://octopuns.blogspot.com/* // @include http://www.powernapcomic.com/* // @include http://blackbird.ashen-ray.com/* // @include http://carciphona.com/* // @include http://ahs-comic.com/* // @include http://www.gogetaroomie.com/* // @include http://gogetaroomie.com/* // @include http://*.thecomicseries.com/* // @include http://www.sleepymaid.com/gallery/displayimage.php* // @include http://sleepymaid.com/gallery/displayimage.php* // @include http://www.squid-ops.com/* // @include http://squid-ops.com/* // @include http://www.endcomic.com/* // @include http://www.thenoobcomic.com/* // @include http://thenoobcomic.com/* // @include http://zizki.com/* // @include http://*.zizki.com/* // @include http://www.schizmatic.com/* // @include http://schizmatic.com/* // @include http://www.bringbackroomies.com/* // @match *://*.blindsprings.com/* // @match *://*.forgottenordercomic.com/* // @include http://www.wtfcomics.com/*archive.html?* // @include http://wtfcomics.com/*archive.html?* // @include http://www.olympusoverdrive.com/index.php?* // @include http://olympusoverdrive.com/index.php?* // @include http://*gucomics.com/* // @include http://www.punksandnerds.com/* // @include http://*.troutcave.net/* // @include http://www.berserkersdaughter.com/* // @include http://gingerhaze.com/nimona/comic/* // @include http://aspect.waywardstudios.net/* // @include http://chirault.sevensmith.net/* // @include http://cucumber.gigidigi.com/* // @include http://www.dorktower.com/* // @include http://nhentai.net/* // @include http://www.hejibits.com/* // @include http://paintraincomic.com/* // @include http://extrafabulouscomics.com/* // @include http://www.feywinds.com/comic/* // @include http://www.omgbeaupeep.com/* // @include http://orgymania.net/* // @include http://mspaintadventures.com/* // @include http://www.mspaintadventures.com/* // @include http://mspfanventures.com/ // @include http://www.mangatown.com/manga/* // @include http://www.legostargalactica.net/* // @include http://*.keenspot.com/* // @include http://dynasty-scans.com/* // @include http://*.dynasty-scans.com/* // @include https://nhentai.net/g/* // @include http://www.marycagle.com/* // @include http://www.sleeplessdomain.com/* // @include http://www.webtoons.com/* // @include http://incase.buttsmithy.com/comic/* // @include http://leylinescomic.com/comics/* // @include http://project-apollo.net/mos/* // @include http://afterstrife.com/?p* // @include https://danbooru.donmai.us/* // @match *://www.mngdoom.com/*/* // @match *://kimchicuddles.com/post/* // @match *://marktrail.com/* // @include http*://www.atomic-robo.com/* // @include http*://www.furaffinity.net/view/* // @include http*://www.furaffinity.net/full/* // @include http*://www.dhscomix.com/comics* // @include http*://www.dhscomix.com/bcomics* // @include http*://www.dhscomix.com/dcomics* // @include http*://www.dhscomix.com/decomics* // @include http*://www.dhscomix.com/dfcomics* // @include http*://www.dhscomix.com/dhscomics* // @include http*://www.dhscomix.com/fcomics* // @include http*://www.dhscomix.com/jcomics* // @include http*://www.dhscomix.com/kcomics* // @include http*://www.dhscomix.com/lcomics* // @include http*://www.dhscomix.com/mercomics* // @include http*://www.dhscomix.com/ocomics* // @include http*://www.dhscomix.com/pcomics* // @include http*://www.dhscomix.com/scomics* // @include http*://www.dhscomix.com/tcomics* // @include http*://www.dhscomix.com/wcomics* // ==/UserScript== // End of includes var dataCache = null; // cache to not read from the disk and parse the configuration on each getData var firstRun = false; // in case GM_ * works but it fails to ask without the "this.", or if they throw an exception when asking try{ GM_getValue = GM_getValue || this.GM_getValue; }catch(e){ GM_getValue = false; } try{ GM_setValue = GM_setValue || this.GM_setValue; }catch(e){ GM_setValue = false; } try{ GM_deleteValue = GM_deleteValue || this.GM_deleteValue; }catch(e){ GM_deleteValue = false; } try{ GM_xmlhttpRequest = GM_xmlhttpRequest || this.GM_xmlhttpRequest; }catch(e){ GM_xmlhttpRequest = false; } try{ GM_registerMenuCommand = GM_registerMenuCommand || this.GM_registerMenuCommand; }catch(e){ GM_registerMenuCommand = false; } try{ GM_openInTab = GM_openInTab || this.GM_openInTab; }catch(e){ GM_openInTab = false; } try{ // fix to use persistent data without pseudogreasemonkey if (!GM_getValue || GM_getValue.toString().indexOf("not supported")>-1) { GM_getValue=function (key,def) { if(!localStorage || !localStorage.hasOwnProperty(key)) return def; var val = localStorage[key]; return val !== undefined ? val : def; }; GM_setValue=function (key,value) { if(!localStorage) return null; return localStorage[key]=value; }; GM_deleteValue=function (key) { if(localStorage) localStorage.removeItem(key); }; } else{ var gmsets = GM_getValue('wcr.settings', null); if(gmsets) dataCache = JSON.parse(gmsets); else{ firstRun = true; GM_setValue('wcr.settings', '{}'); dataCache = {}; } } if(!GM_openInTab) GM_openInTab = window.open; if(!GM_registerMenuCommand || GM_registerMenuCommand.toString().indexOf("not supported")>-1){ GM_registerMenuCommand = function(txt, fun){ var boton = document.createElement('button'); boton.innerHTML = txt; setEvt(boton, 'click', fun); document.body.appendChild(boton); }; } }catch(e){} var prefetchSize = confPrefetchSize([defaultSettings.prefetchBack, defaultSettings.prefetchNext]); //number of prefetched pages ahead in each direction var prefetchSizeStart = confPrefetchSizeStart([defaultSettings.prefetchBackStart, defaultSettings.prefetchNextStart]); //number of prefetched pages in each direction the first time var prefetchNoNext = confBool('prefetchNoNext', true); var keepLayout = confKeepLayout(defaultSettings.fullLayout); //decide to keep the original layout of the page (true) or use a clean minimalistic layout (false) var debug = confDebug(defaultSettings.debugMode); //alerts on errors, and shows some of the currently cache'd pages/images with the "," key var showButtons = confShowButtons(defaultSettings.showButtons); //show or hide the buttons (back/next, bookmarks, settings, etc...) var leftImageClick = confLeftImageClick(defaultSettings.clikLeftHalfGoesBack); //specifies if clicking the left half of the image will take you to the previous page var goToBookmark = confBool('goToBookmark', defaultSettings.goToBookmark); var useHistoryAPI = confBool('useHistoryAPI', true); var moveWhileLoading = confBool('moveWhileLoading', defaultSettings.moveWhileLoading); var maximgs = []; // keep only this number of images loaded behind and ahead of the current one so as not to eat memory maximgs[1] = Math.max(23, prefetchSize[1]); maximgs[-1] = Math.max(23, prefetchSize[0]); var usarb64 = confBool('b64_images', false); /* paginas[i] = { url: //'substring' or /regexp/ that matches the url img: //gets the element containing the desired image (not just the src, but the whole ) //if not present, searches an img with a src containing some common strings like "/comics/" or "/strips/" //'string' means "the element whose src starts with 'string'" back: next: //get the href of the back and next links //if not present, defaults to links containing "back"|"prev" / "next" in the element's innerHTML //'string' means "the href of the element that satisfies 'string' (as an XPath expression) extra: //optional array of additional content, as a 'literal string' or taken from the HTML with, ['XPath'], [['CSS']], [/regexp/, group number], or other possibilities as documented below bgcol: txtcol: //override the default colors of the page for readability or aesthetics //'#RRGGBB', '#RGB', 'rgb(r, g, b)' js: //executes a custom function after a page change, receiving the direction (1=forward, -1=back, 0 the first time) as a parameter scrollx: scrolly: //tells the top-left coordinates for scrolling after changing page (default = U/L) //'U', 'D', 'L', 'R' and 'M' are to show the top, bottom, left, right and middle of the image //or it can be a number (in pixels) or a function that returns a number layout: //forces the default behaviour for the layout (true=keep the original, false=clean it) xelem: //string with an XPath expression to get the element to be used as placeholder for the extra content //used only when keeping the original layout } img/back/next/extra[i] can be either: 'string', ['XPath expression that returns the first element found'], ['XPath expression that returns an array of elements', 'string to put between each element', ?first_index, ?last_index], [['CSS selector that returns the first element found']], [/regular expression/, group number to get the desired content] function(html_of_requested_page, position_relative_to_the_starting_page){ return content; } a 'string' is interpreted as part of a default XPath expression for img/back/next, or a literal string for extra[i] */ var paginas = [ { url: 'penny-arcade.com', img: [['#comicFrame img']], fixurl: function(url, img, link, pos){return url.replace("http:","");}, extra: [[['.title h2']]], style: '#bb,#header{position:relative;}' }, { url: 'xkcd.', img: ['//div[@id="comic"]//img'], first: '.="|<"', last: '.=">|"', extra: ['
', ['//div[@id="ctitle"]'], function(html, pos) { var href = xpath('//div[@id="comic"]//a/@href', html); return '
' + (href.indexOf('xkcd') >= 0 ? 'Large version' : 'Bonus Link!') + ''; }, function(html, pos) { var comic = xpath('//div[@id="comic"]', html); var img = comic.getElementsByTagName('img')[0]; img.parentNode.removeChild(img); return comic; }, function(html, pos){ var nr = link[pos].match(/(\d+)\/$/)[1]; var url = 'http://www.explainxkcd.com/wiki/index.php/' + nr; return 'Explain Xkcd'; }], bgcol: '#fff' }, { url: '*.dilbert.com', img: [['.img-comic']], back: '@alt="Older Strip"', next: '@alt="Newer Strip"' }, { url: 'explosm.net/comics', img: [['#main-comic']], extra: [['//small[@class="author-credit-name"]/../../..'], [/[', ['//h3/*/text()'], ']

', [/"storycontent"[\s\S]+?([\s\S]+?)<\/div>/i, 1]] }, { url: 'thedoghousediaries.com', img: [['#imgdiv img']], back: [['#previouslink']], next: [['#nextlink']], extra: [[['#title-signoff-share']]] }, { url: /erfworld\.com\/(page\/|$)/, img: ['//div[@class="entry"]//img'], back: 'contains(.,"Older")', next: 'contains(.,"Newer")', extra: [['//div[@class="post"]/*', '', 0, 2], ['//div[@class="post"][1]//div[@class="entry"]/p[not(.//img)]', ''], ''] }, { url: 'erfworld.com', extra: [[['.post>h2']], ['//table[@class="PxgGalleryTable"]//p[not(img)]', '']] }, { url: 'es.juanelo.net/archivo', img: 'http://es.juanelo.net/tiras/', back: '.="« Anterior"', next: '.="Siguiente »"', style: '#page{width:1210px;} .narrowcolumn{width:810px;}' }, { url: 'es.juanelo.net/show', img: ['//div[@id="tirashow"]//img[starts-with(@src, "http://es.juanelo.net/tiras/")]'], back: ['//div[@id="tirashow"]//a[.="« Anterior"]/@href'], next: ['//div[@id="tirashow"]//a[.="Siguiente »"]/@href'], style: '#page{width:1210px;} .narrowcolumn{width:810px;}' }, { url: 'es.juanelo.net/20', img: 'http://es.juanelo.net/tiras/', back: 'contains(.,"«")', next: 'contains(.,"»")', extra: [[['img[src*="/tiras/"]', '
', 1]], [['.post>h2']], [['.entry>p']]], style: '#page{width:1210px;} .narrowcolumn{width:810px;}', bgcol: '#334255' }, { url: 'readms.net', img: [['#manga-page']], back: [['.previous a']], next: [['.next a']], style: '.subnav[style*="fixed"]{display: none;}#wcr_imagen{max-width:none;}#reader-sky{z-index:-1;}', scrollx:'R', layout: true }, { url: 'terrorisland.net', extra: [['//div[@class="commentary"]', '']] }, { url: 'drmcninja.com', img: 'http://drmcninja.com/comics/', extra: ['
', ['//select[@id="series_select"]'], ['//select[@id="page_select"]'], [['.post-comic .entry']]], js: function(dir){ var selSer = xpath('//div[@id="wcr_div"]//*[@id="series_select"]'); setEvt(selSer, 'change', function(){ exec("document.location.href = '/archives/comic/'+series_arr["+selSer.selectedIndex+"].posts[0];"); }); selSer.style.visibility = 'visible'; selSer.disabled = false; var selPag = xpath('//div[@id="wcr_div"]//*[@id="page_select"]'); setEvt(selPag, 'change', function(){ document.location.href = '/archives/comic/'+selPag.value; }); } }, { url: 'gpf-comics.com', img: '/comics/', back: './img[@alt="Previous Comic"]', next: './img[@alt="Next Comic"]' }, { url: 'daisyowl.com', img: ['//div[@align="center"]//img[starts-with(@src,"/comic_images/")]'] }, { url: 'hyperdeathbabies.com', img: 'anomaly/' }, { url: 'amultiverse.com', img: [['#comic img']], extra: [['//div[@class="post-content"]']], js: function(){ if(keepLayout) get('comic').style.height = get('wcr_div').offsetHeight + 'px'; }, xelem: '//div[@id="content"]//div[@class="post-content"]', style: '#comic button{float:none;}' }, { url: 'wondermark.com', img: 'http://wondermark.com/c/', back: '@rel="prev"', next: '@rel="next"', txtcol: '#fff' }, { url: 'amazingsuperpowers.com', img: function(html, pos){ try{ return selCss('#comic-1 img', html); } catch(e){ if(selCss('#comic-1 #comic-short', html)) return selCss('img', html); } }, extra: [[['#comic-1 #comic-short']], function(html, pos){ var href = selCss('#question a', html).href; var htmlHidden = syncRequest(href, pos); return contenido(htmlHidden, [['#comic > *', '']]); }, [['.post']]], style: '#page,#header{width:auto;}', layelem:'//div[@id="comic-1"]' }, { url: 'm.fanfox.net', img: ['//img[@id="image"]'], back: ['//select/option[@selected]/preceding-sibling::*[1]'], next: ['//div[@id="viewer"]/a'], scrollx:'R' }, { url: 'fanfox.net', img: ['//img[@id="image"]'], back: function(html, pos){ var href = contenido(html, ['//a[contains(@class, "prev_page")]/@href'], pos); if(href.indexOf('javascript')<0){ if(href.indexOf('/')<0) return link[pos].replace(/[^\/]*$/, href); return href; } return contenido(html, ['//span[contains(., "Previous Chapter")]/../a/@href'], pos).replace(/\d+\.html/, '999.html'); }, next: function(html, pos){ var current_page = parseInt(html.match(/var current_page=(\d+);/)[1]); var final_page_of_chapter = parseInt(html.match(/var total_pages=(\d+);/)[1]); if(current_page < final_page_of_chapter){ //just load next page var href = contenido(html, ['//a[contains(@class, "next_page")]/@href'], pos); if(href.indexOf('/')<0) return link[pos].replace(/[^\/]*$/, href); return href; } return contenido(html, ['//span[contains(., "Next Chapter")]/../a/@href'], pos); }, extra: [function(html, pos){ if(extra[0]) return extra[0].replace(/(<\/select>)[\s\S]*/i, '$1'); return contenido(html, ['//select[@id="bottom_chapter_list"]'], pos); }, ' ', [['select.m']], '', function(html, pos){ var alt = xpath('//img[@id="image"]/@onerror', html).replace(/^.+?'|'$/g, ''); return 'Image details', [['#posts']], ], layelem:'//div[@id="posts"]/div[1]', js: function(dir){ var selExtras = selCss('#wcr_extra'); selCss('#wcr_div').insertBefore(selExtras, null); // Doesn't currently work. // var thumbs = selCss('.post-preview>a',selExtras, true); // for (var i = 0; i < thumbs.length; i++){ // thumbs[i].href = "##"+i; // } }, }, { url: 'mngdoom.com', img: function(html, pos){ var pageCh = link[pos].match(/(\d+)\/(\d+)$/); var chapter, page; if (pageCh) { chapter = pageCh[1]; page = pageCh[2]; } var images = JSON.parse(html.match(/var images = ([^;]*)/)[1]).map(x=>x.url); return images[page-1]; }, back: function(html, pos){ var pageCh = link[pos].match(/(\d+)\/(\d+)$/); var chapter, page; if (pageCh) { chapter = +pageCh[1]; page = +pageCh[2]; } var images = JSON.parse(html.match(/var images = ([^;]*)/)[1]).map(x=>x.url); var prev_ch = html.match(/var prev_chapter_url = '([^']*)'/); if (page <= 1) { return prev_ch[1]; } else { return link[pos].replace(/(\d+)\/(\d+)$/, chapter + "/" + (page - 1)); } }, next: function(html, pos){ var pageCh = link[pos].match(/(\d+)\/(\d+)$/); var chapter, page; if (pageCh) { chapter = +pageCh[1]; page = +pageCh[2]; } var images =JSON.parse(html.match(/var images = ([^;]*)/)[1]).map(x=>x.url); var next_ch =html.match(/var next_chapter_url = '([^']*)'/); if (page >= images.length-1) { return next_ch[1]; } else { return link[pos].replace(/(\d+)\/(\d+)$/, chapter + "/" + (page+1)); } }, }, { url: 'kimchicuddles.com/post/', img: [['figure.photo-hires-item img']], back: [['.previous-button']], next: [['.next-button']], first: [['.first-button']], last: [['.latest-button']], }, { url: 'marktrail.com', img: [['#comic img']], }, { url: 'atomic-robo.com', img: [['#cc-comic']], back: [['.cc-prev']], next: [['.cc-next']], first: [['.cc-first']], last: [['.cc-last']], style: '#wcr_imagen{height:auto !important;width:auto !important;}' }, { url: 'furaffinity.net', img: [['#submissionImg']], back: ['//span[@class="parsed_nav_links"]//a[contains(.,"PREV")]'], next: ['//span[@class="parsed_nav_links"]//a[contains(.,"NEXT")]'], first: ['//span[@class="parsed_nav_links"]//a[contains(.,"FIRST")]'], extra: [['//table[@class="maintable"]//tbody//tr//table[@class="maintable"]']] }, { url: 'dhscomix.com/comics', //Random Encounters img: ['//div[@id="content"]//img'], extra: [['//div[@id="content"]']], back: 'img[contains(@src, "nav_prevpage")]', next: 'img[contains(@src, "nav_nextpage")]', //Work around for multiple comic images on a page style: '#wcr_imagen{display: none !important;}\ndiv#content p:nth-child(1){display: none !important}', //Hides img and displays only extra js: function(dir){ //Copied from Webtoon's entry. Thanks to who ever did that // Makes it so anything within extra will be nav-clickable var elemImagen = document.querySelectorAll('#wcr_extra'); setEvt(elemImagen, 'click', imgClick); setEvt(elemImagen, 'mousemove', imgCursor); }, }, { url: 'dhscomix.com/bcomics|dhscomix.com/dcomics|dhscomix.com/decomics|dhscomix.com/dfcomics|dhscomix.com/dhscomics|dhscomix.com/fcomics|dhscomix.com/jcomics|dhscomix.com/kcomics|dhscomix.com/lcomics|dhscomix.com/mercomics|dhscomix.com/ocomics|dhscomix.com/pcomics|dhscomix.com/scomics|dhscomix.com/tcomics|dhscomix.com/wcomics', //All the other DHS Comix Comics img: ['//div[@id="content"]//img'], extra: [['//div[@id="content"]']], back: 'img[contains(@src, "previous")]', next: 'img[contains(@src, "next")]', //Work around for multiple comic images on a page style: '#wcr_imagen{display: none !important;}\ndiv#content p:nth-child(1){display: none !important}', //Hides img and displays only extra js: function(dir){ //Copied from whoever did Webtoon's entry // Makes it so anything within extra will be nav-clickable var elemImagen = document.querySelectorAll('#wcr_extra'); setEvt(elemImagen, 'click', imgClick); setEvt(elemImagen, 'mousemove', imgCursor); }, } // End of sites /* , { url: '', img: '', back: '', next: '' } , { url: '', img: '', back: '', next: '', first: '', last: '', extra: [[['']]], fixurl: function(url, img, link){ }, js: function(dir){ }, scrollx:'R', xelem: '', layelem:'', txtcol: '', bgcol: '', style: '', layout: true } */ ]; /* xpath: X = element X @A = attribute A * = wildcard . = self, innerHTML when used in conditions, use /text ()to return the text X[Y] = X that complies with Y (Y can reference attributes or children) X[num or last()] = the X which is the n-th child of his father .. = parentNode / = son // = descendant contains(x, y) = x.indexOf(y)>=0 starts-with(x, y) = x.indexOf(y)==0 name() = tag name IN UPPER CASE X | Y = what matches the xpath X or the Y http://xpath.alephzarro.com/content/cheatsheet.html http://www.zvon.org/xxl/XPathTutorial/General/examples.html */ var imagen = new Array(); // src of the image[i] var imagenOK = [true]; // true if image[i] is loaded var imagen64 = new Array(); // content of the image[i] as data:url in base64 var imgTitle = new Array(); // the alt text of the image [i] var titulo = new Array(); // title of the page [i] var link = new Array(); // url of the page [i] var extra = new Array(); // extra content of the page[i] var cache = {}; // Cache of loaded pages. Used on ajax sites. var extraData = {}; // Extra data for usage in a site implementation var posActual = 0; // current position relative to where it started var prefetcheado = new Array(); prefetcheado[-1] = prefetcheado[1] = 0; var layoutDefault = '
'+ ''+ '
' + '
' + '
' + '
'+ '
'+ '<< First '+ ' '+ ' '+ 'Last >>'+ '

'+ '
'+ ''+ ' '+ '
'+ '
'+ ''+ '

'+ '
'+ ' '+ ' '+ ' '+ ''+ '
'+ '
'+ ''+ ''+ '
'; // instead of replacing the body.innerHTML, put the `layoutdefault` where the image was and leave the rest of the page intact function layoutIntacto(){ // make the links to the previous pages / sgte work like the back / next buttons if(confBool('overwrite_links', true)){ try{ var next = contenido(document.documentElement.innerHTML, getNext, 0); var linksNext = xpath('//*[@href="'+next+'"]', document, true); for(var i=0;i]*href *= *"([^\"]+)"([^<]|<[^\/]|<\/[^a])*(back(?!ground)|prev)/i, 1]; var getNext = [/]*href *= *"([^\"]+)"([^<]|<[^\/]|<\/[^a])*next/i, 1]; var getFirst = [/]*href *= *"([^\"]+)"([^<]|<[^\/]|<\/[^a])*first/i, 1]; var getLast = [/]*href *= *"([^\"]+)"([^<]|<[^\/]|<\/[^a])*(last|latest|newest|today)/i, 1]; var getExtras = false; // (optional) getters array to put them in the extra div var bgColor = false, txtColor = false; // (optional) force background / text color var funcionJs = false; //(optional) execute a function after displaying a page var scrollx = confVal('scrollx', 'L'); // where to auto scroll the page (L / M / R of the image, or pixels) var scrolly = confVal('scrolly', 'U'); // ditto (U/M/D) var extraElement = false; // where the extra is put when the full layout is used var fixUrl = false; // f (url, origin (link / img)) that is applied to the links and src of the image, for rare pages (eg, in sinfest the link in the www points to the non-www and the non-www redirects to the www) var layoutElement = null; // where everything is put when using the full layout var style = ''; // content of a '; document.body.appendChild(divsets); initLayout(opsGeneral, 'general'); initLayout(opsLayout, 'layout'); initSitio(propsSitio); initTeclas(teclas); //set events for tabs / save / cancel var tabs = xpath('//div[@id="wcr_settings_links"]/span', document, true); for(var i=0; i0 ? 'L' : 'R'; else val = val>0 ? 'D' : 'U'; } if(typeof(valdef)=='number'){ get('wcr_sel_layout__offset_'+o+'_def').value = valdef<0 ? -valdef : valdef; if(o=='scrollx') valdef = valdef>0 ? 'L' : 'R'; else valdef = valdef>0 ? 'D' : 'U'; } } get(id).value = val; get(id+'_def').value = valdef; if(!o.indexOf('cursor_custom_')){ setEvt(id+'_def', 'mouseover', function(evt){ evt.target.style.cursor = cursorUrl(evt.target.value); }); setEvt(id, 'mouseover', function(evt){ evt.target.style.cursor = cursorUrl(evt.target.value); }); } else if(!o.indexOf('cursor_')){ setEvt(id+'_def', 'mouseover', function(evt){ evt.target.style.cursor = confCursor(null, null, evt.target.value); }); setEvt(id, 'mouseover', function(evt){ evt.target.style.cursor = confCursor(null, null, evt.target.value || get(evt.target.id+'_def').value); }); } } } //initialize site values and events function initSitio(props){ var lista = getConfPagina('lista'); var selConf = get('wcr_sel_confpag'); for(var i=0; i'+ (lista[i][0]=='d'?'(default) ':'(custom) ')+ lista[i].substr(3)+ ''; } if(!lista.length){ selConf.innerHTML += ''; } setEvt('wcr_btn_delconfpag', 'click', function(evt){ if(!confirm('Are you sure you want to delete these settings?')) return; var customs = getData('confpags', {}, 'custompages'); var nombre = unescape(get('wcr_sel_confpag').value); delete customs[nombre]; setData('confpags', customs, 'custompages'); if(getData('confpag') == nombre) delData('confpag'); var selConf = get('wcr_sel_confpag'); selConf.removeChild(selConf.options[selConf.selectedIndex]); if(selConf.options.length == 2){ selConf.innerHTML += ''; } selConf.selectedIndex = selConf.options.length-1; initValoresSitio(props, selConf.value); }); setEvt('wcr_btn_editconfpag', 'click', function(evt){ selConf.selectedIndex = 0; initValoresSitio(props, selConf.value); }); for(var p in props){ var seltipo = get('wcr_sitio_tipo_'+p); setEvt(seltipo, 'change', function(evt){ cambiaTipo(evt.target); }); } var confActual = initValoresSitio(props, getData('confpag', '')); selConf.value = escape(confActual); setEvt(selConf, 'change', function(evt){ initValoresSitio(props, unescape(evt.target.value)); }); setEvt('wcr_btn_add_extra', 'click', function(evt){ var p = 'extra_'+Number(new Date()); trExtraConfSitio(p, props.extra); var seltipo = get('wcr_sitio_tipo_'+p); cambiaTipo(seltipo); }); } //populates the site conf table with the values of a specific conf function initValoresSitio(props, conf){ var pag = null; if(conf != 'new'){ //If it is new, current values are preserved pag = getConfPagina(conf); for(var p in props){ if(p=='extra'){// is an array, get into each try{ var extrasViejos = xpath('//tr[@class="wcr_extras"]', document, true); for(var i=0; i1 ? '1' : ''; if(valor.length>1) get(base+'_xp_glue').value = valor[1]; if(valor.length>2) get(base+'_xp_first').value = valor[2]; if(valor.length>3) get(base+'_xp_last').value = valor[3]; } else if(isArray(valor[0])){ //css valor = valor[0]; seltipo.value = 'css'; get(base+'_css_val').value = valor[0]; if(get(base+'_css_arr')) get(base+'_css_arr').value = valor.length>1 ? '1' : ''; if(valor.length>1) get(base+'_css_glue').value = valor[1]; if(valor.length>2) get(base+'_css_first').value = valor[2]; if(valor.length>3) get(base+'_css_last').value = valor[3]; } else{ //re seltipo.value = 're'; get(base+'_re_val').value = valor[0]; if(valor.length>1) get(base+'_re_grp').value = valor[1]; } break; case 'function': //fn seltipo.value = 'fn'; //get the "^func..{" and the "}$" var fn = valor.toString(); fn = fn.replace(/^.+?\{(\s*[\r\n]+)*|\s*\}$/g, ''); fn = fn.replace(new RegExp('^' + fn.match(/^\s*/), 'mg'), ''); get(base+'_fn_val').innerHTML = fn; break; case 'boolean': seltipo.value = 'bool'; get(base+'_bool_val').value = valor; break; case 'number': seltipo.value = 'num'; get(base+'_num_val').value = valor; break; } } } catch(e){ error('rellenarSitio.'+p+': ', e); } } } //show the corresponding inputs and hide the q no when changing the selector type for a prop of the conf of a site function cambiaTipo(sel){ var clave = sel.id.substr('wcr_sitio_tipo_'.length), tipo = sel.value; var elems = xpath('//*[starts-with(@id,"wcr_sitio_valor_'+clave+'")]', document, true); for(var i=0; i0 ? '' : 'none'; } //initialize key values and events function initTeclas(teclas){ var input, inputaux, hiddens = ['keyCode', 'ctrlKey', 'shiftKey', 'altKey']; teclado = getTeclas(); //in case they changed the conf from another page for(var t in teclas){ var teclasAlternativas = teclado[t] || [{}]; if(!isArray(teclasAlternativas)) teclasAlternativas = [teclasAlternativas]; for(var i=0; i<2; i++){ input = get('wcr_tecla_'+i+'_'+t); var tecla = teclasAlternativas[i] || {}; input.value = tecla.name || ''; for(var h=0; h= 16 && evt.keyCode <= 18 || evt.keyCode == 27) return; //ctrl/shift/alt or ESC (works weird?) if(evt.keyCode == 8){ //BACKSPACE, leave the action without a key for(var h=0; h'+ ''+ ''+ 'Default settings'+ 'Settings for '+document.location.host.replace(/^www\./, '')+''+ ''; for(var o in ops){ var op = ops[o]; if(!o.indexOf('_grp_')){ html += ''+ ''+op.desc+''+ ''; } else{ var opts = ''; if(op.vals) for(var v in op.vals){ opts += ''; } html += ''+ ''+op.desc+''+ ''+ (op.vals ? ('') : ('') )+''+ ''+ (op.vals ? ('') : ('') )+''+ ''; } } html += ''; // be able to hide divs / buttons? (first / last, bookmarks, last visited, toggle layout) // if things are hidden, make sure they don't fail when trying to use them return html; } //generate the html of the site conf function htmlSitio(props){ var html = '
Current site settings: '+ ''+ ''+ ''+ '

'; for(var p in props){ html += ''; if(p=='extra') html += ''; else{ var tds = tdsConfSitio(p, props[p]); html += ''; } } html += '
'+props[p].desc+'
'+tds[0]+''+tds[1]+'

Hover over a textbox for its meaning and an explanation on how to use it

For a detailed guide on adding new sites, check
this thread in the script site'; /*todo: add tests 4th `td` with test button and an invisible `tr` below for the result request link [posActual] and apply that getter to be able to export / import this thing to be able to export this site or all customs to merge repeated asking if to keep the current or imported */ return html; } //returns the "innerhtml"s of the "tds" to specify the content function tdsConfSitio(p, prop){ var tds = ['', '']; for(var t in prop.tipos) tds[0] += ''; tds[0] = ''; for(t in prop.tipos) for(var v in prop.tipos[t]){ if(v=='desc') continue; tds[1] += '<'+prop.tipos[t][v].elem+' id="wcr_sitio_valor_'+p+'_'+t+'_'+v+'"'; for(var a in prop.tipos[t][v]) if(a!='elem' && a!='html') tds[1] += ' '+a+'="'+prop.tipos[t][v][a]+'"'; tds[1] += prop.tipos[t][v].html ? '>'+prop.tipos[t][v].html+'' : (prop.tipos[t][v].elem == 'textarea' ? '>' : '/>'); } return tds; } //insert a `tr` to add more extra content function trExtraConfSitio(p, prop){ var tr = document.createElement('tr'); tr.className = 'wcr_extras'; tr.id = 'wcr_tr_sitio_'+p; var tds = [ document.createElement('td'), document.createElement('td'), document.createElement('td')]; var tdsConf = tdsConfSitio(p, prop); tds[0].innerHTML = '
'+ ''+ ''+ ''+ '
'; tds[1].innerHTML = tdsConf[0]; tds[2].innerHTML = tdsConf[1]; tr.appendChild(tds[0]); tr.appendChild(tds[1]); tr.appendChild(tds[2]); var trAfterExtra = get('wcr_tr_sitio_xelem'); trAfterExtra.parentNode.insertBefore(tr, trAfterExtra); var seltipo = get('wcr_sitio_tipo_'+p); setEvt(seltipo, 'change', function(evt){ cambiaTipo(evt.target); }); setEvt('wcr_btn_del_'+p, 'click', function(evt){ var tr = evt.target.parentNode.parentNode.parentNode; tr.parentNode.removeChild(tr); }); setEvt('wcr_btn_up_'+p, 'click', function(evt){ var tr = evt.target.parentNode.parentNode.parentNode; var otro = tr.previousSibling; if(otro.id.indexOf('wcr_tr_sitio_extra_')===0){ tr.parentNode.insertBefore(tr, otro); } }); setEvt('wcr_btn_down_'+p, 'click', function(evt){ var tr = evt.target.parentNode.parentNode.parentNode; var otro = tr.nextSibling; if(otro.id.indexOf('wcr_tr_sitio_extra_')===0){ tr.parentNode.insertBefore(otro, tr); } }); } //generate the html of the keyboard conf function htmlTeclas(teclas){ var html = ''+ ''+ ''+ ''+ ''; for(var t in teclas) html += ''+ ''+ ''+ ''+ ''; html += '
'+ 'KeyAlternate Key
'+teclas[t][0]+'

Press BackSpace to unset a key'; return html; } //save everything from the configuration screens function guardarSettings(teclas, props, tiposUp, opsLayout){ try{ //save keys var hiddens = ['keyCode', 'ctrlKey', 'shiftKey', 'altKey']; for(var t in teclas){ teclado[t] = []; for(var i=0; i<2; i++){ teclado[t][i] = { name: get('wcr_tecla_'+i+'_'+t).value, keyCode: get('wcr_tecla_'+i+'_'+t+'_keyCode').value }; for(var h=1; h0) setData(o, valdef, 'default'); if(o.indexOf('prefetch_')<0 || val === '' || val.match(/^\d+$/) && Number(val)>0){ if(val != '') setData(o, val); else delData(o); } } //save site var conf = unescape(get('wcr_sel_confpag').value); if(conf == '' || conf[0]=='d') setData('confpag', conf); else{ //es new o un custom var ok = true; var tipourl = get('wcr_sitio_tipo_url').value; var nombre = 'c'+tipourl[0]+':'+get('wcr_sitio_valor_url_'+tipourl+'_val').value; var customPag = {}; for(var p in props){ if(p=='extra'){ try{ var xx = []; var extras = selCss('tr.wcr_extras', document, true); for(var i=0; i1){ if(!elems[1].value.match(/^\d+$/) || Number(elems[1].value)===0){ alert(p+': "'+elems[1].value+'" is not a valid number'); ok = false; } else valor.push(Number(elems[1].value)); } break; case 'xp': case 'css': valor = [elems[0].value]; if(elems[1] && elems[1].value){ //if it's an array ... valor.push(elems[2].value); if(elems[4].value && !elems[3].value) elems[3].value = '0'; if(elems[3].value){ var num = Number(elems[3].value); if(!elems[3].value.match(/^[-\d]+$/) || isNaN(num)){ alert(p+': "'+elems[3].value+'" is not a valid number'); ok = false; } else valor.push(num); } if(elems[4].value){ num = Number(elems[4].value); if(!elems[4].value.match(/^[-\d]+$/) || isNaN(num)){ alert(p+': "'+elems[4].value+'" is not a valid number'); ok = false; } else valor.push(num); } } if(tipo=='css') valor = [valor]; break; case 'fn': valor = xpath('//select[@id="wcr_sitio_tipo_'+p+'"]/option[@value="fn"]').innerHTML+'{\n'+ elems[0].value + '\n}'; try{ eval('f='+valor); } catch(e){ alert(p+': "'+valor+'" is not a valid function ('+e+')'); ok = false; } break; case 'bool': valor = elems[0].value == 'true'; break; case 'num': valor = Number(elems[0].value); if(isNaN(valor)){ alert(p+': "'+elems[0].value+'" is not a valid number'); ok = false; } break; } if(p=='url'){ if(!valor){ alert('url: this field is obligatory'); ok = false; } else{ if(tipo=='str') re = strToRegexp(valor); else eval('re = '+elems[0].value); if(!document.location.href.match(re)){ alert('url: the expression '+elems[0].value+' doesn\'t match the current URL'); ok = false; } } } if(!ok) throw new Error('error'); return {tipo: tipo, valor: valor}; } //hide the other tabs and display a specific one (passed) function cambiarTabSettings(nombre){ var tabs = xpath('//div[@id="wcr_settings_content"]/div', document, true); for(var i=0; i0; } //see if the firefox engine is used function isFirefox(){ return navigator.userAgent.indexOf('Gecko/')>0; } //configuration screen that appears when zoom is enabled but is not configured function mostrarSettingsZoom(){ try{ var html = ''; var cbs = { achw: 'Shrink wide images to fit in the width of the screen', achh: 'Shrink high images to fit in the height of the screen', agrw: 'Expand narrow images to use the width of the screen', agrh: 'Expand short images to use the height of the screen' }; for(var p in cbs) html += ' '+ '
'; var txts = { bordex: 'Pixels to leave as a border to the left and right', bordey: 'Pixels to leave as a border above and below the image' }; for(p in txts) html += ' '+txts[p]+'
'; html += '
'+ '
'; var divsets = document.createElement('div'); divsets.id = 'wcr_settings'; divsets.style.textAlign = 'center'; divsets.innerHTML = '
'+ '
'+ '
How do you want the images to be fitted?

'+ '
'+html+'

'+ 'These (and more) settings can be changed later by clicking the "Settings" button
'+ '
'+ '
'+ ''+ '
'+ '
'+ ''; document.body.appendChild(divsets); // set the size and position var popup = get('wcr_settings_popup'); var top = document.documentElement.scrollTop; if(!top) top = document.body.scrollTop; popup.style.top = (top+10) + 'px'; popup.style.marginLeft = -popup.offsetWidth/2 + 'px'; //initialize values for(p in cbs){ eval('var x = '+p); get('wcr_set_cb_'+p).checked = x; } setEvt('wcr_set_btn_guardar', 'click', function(){ //save the confs and set the variables var dom = get('wcr_set_cb_def').checked ? 'default' : undefined; for(var p in cbs){ eval(p+' = '+get('wcr_set_cb_'+p).checked); setData(p, get('wcr_set_cb_'+p).checked ? 1 : 0, dom); } for(p in txts){ var val = Number(get('wcr_set_txt_'+p).value); if(isNaN(val)) continue; eval(p+' = '+val); setData(p, val, dom); } document.body.removeChild(divsets); fitImagen(); scrollear(); }); setEvt('wcr_set_btn_disable', 'click', function(){ if(confirm('Are you sure you want to disable Webcomic Reader on this site?\n'+ '(It can be re-enabled later with the Greasemonkey menu)')){ setData('confpag', 'dis'); redirect(link[posActual]); } }); } catch(e){ alert('Error while initializing the zoom settings window: ' + e); if(get('wcr_settings')) document.body.removeChild(get('wcr_settings')); } } run_script(); })(); /* alert( 0*1+ //'Bug fixes (Firefox)', 0*2+ //'Bug fixes (Other browsers)', 0*4+ //'New features', 0*8+ //'New sites', 0*16+ //'Fixes for old sites', 0*32+ //'Graphic changes', 0*64+ //'New options', 0*128+ //??? 0 ); */ /*todo: easy way to extract several pages from a single request (blogs, reddit, old pages, etc) the img would have to retrieve a list of results an extra_context function is added: function (html, pos, relpos) which returns the context on which the extras are searched for each item the urls would be filled with ## post-relative-to-the-page back / next search for the link normally the `prefetcheador` advances the n by one be able to define a container for each extra [v2] extras: {selector: [things, masks]} to be able to make fixed extras (they are filled once and they are not looked for or touched anymore) [v2] add a container of fixed extras, fill it in the js or with extras: {fixed container: [function (html, pos) {if (pos) return ''; return selector;}]} to be able to read extras by ajax? function () {request synchronous} In site settings, button to export to copypasteable format to the script option to define how many links are preloaded, separated from how many images pure html is preloaded, and in a separate process the images load link, if (! loadingimg) loadimgs -> first load not loaded and go to N select with the pages loaded, differentiating those with img list change loaded image condition to change page btnback and btnnext do not advance if the next page has not been loaded jump straight to a page if it works, and start loading the imgs around change condition to take an img of the loaded ones (currently it maintains the current ±23) use the magic doc to parse the stuff ajaxeadas, so it does not load the imgs make the parser functions receive the html and the doc make an htmlToDoc function instead of just keeping the imgs in the loaded imgs thing, add the extras next/prev chapter (+ keys) support AMR in minimalistic? have a "do not delete" selector list for each "do not delete" item, add it to a list along with its ancestors for each item in the list, delete all siblings that are not in the list tb could support the Greased Webcomic Manager change the way data is recorded (current object grows a lot, mine weighs 50kb) 1 setting per site 1 setting with default 1 setting with the list of all settings use a "settings" variable that has all the conf loaded, same as defaultSettings replace the random variables that are used now use the names that are used to save map coherentNames -> savedNames remake the code in OOP style class that handles the script per se class for the conf of a page class for settings class for settings screen to be able to list all the sites that I review in some way when saving the last page visited, save: url, title, date, img.src and next list with the page and the last date that was reviewed (à la GreasedWebcomicManager?) warn that there is a new page if I change the img.src or next button to force q to review a page or all of the list show a star for favorites, clickable for (un) favorite be able to disable sites button to switch between see all / favorites / non-favorites checks to show [favorites], [non-favorites], [disabled], [new page] button to add / remove from favorites button to disable script on this site button to force check of new page in one / all pages just check the ones that don't have a new page key to go to the next key to go to a random "comics of the day" page use a special page to redo it (@include *wcr_latest_comics. in ffox about:blank?wcr _..., if not google.com/wcr_... (404)) with the images of the day of my comics each with back / next boy (on the sides and / or click on img)? show only the new ones? (mark as read?) have next to (hidden?) the complete list of pages "fullchapterloader" mode show all images one under another move forward only advance (posActual++, load more pages ...) while scrolling show the images and the extra in a div put the buttons (settings / change mode) above message at the end when there are no more pages (or link to the page without img) ????: when going back, check if the next one is the same, and if it is not load it in between should shift everything back to fill the hole ... or something like that ... so difficult ... instead of filling in, advise? ????: delete the extras on page 0? make adding sites easier be able to switch between @include * on / off mode on: only start on explicitly included pages (if (! getConfPag) break;) off: try to always start (like now) site settings 4th column with test button in props site have a test element, it can be a function or true for the default test default: convert to getter and get content as string add tr with the result (td [1] "Test results:" align-right, td [2,3] content, td [4] button hide) to be able to export / import this variable to merge repeated asking if to keep the current or imported to be able to export / import all the pages or only this to be able to import from other pages (userscripts forum?) @include http://userscripts.org/topics/* random person posts their exported pages the script finds them and clicks them, onclick they are imported to centralize this on one page? lemontecho? :P random people upload their settings can be viewed and imported have an "official" configuration maintained by me have an autoupdater to download that version wizard to add sites accessible from the gm menu ask to click the image and the links load the previous page and follow, and look for img / links that match the ones marked search by attributes, patterns, etc? then ask the most basic things go to the confs editor keep saving the messages of the changes of the not notified versions? leave the layout more custom-ready-for-what's-good? array of layouts custom functions for "events" that modify buttons instead of "toggle" button, put a select with the layouts add pages http://www.viruscomix.com/subnormality.html include subreddits instead of all reddit http://www.harrington-artwerkes.com/Lana5.htm http://eecomics.net/?strip_id=152 http://www.shadowgirlscomic.com/comics/maxmachine-interface/ http://www.pantheracomic.com/?p=214 http://dimensiondust.blogspot.com/search?updated-max=2010-06-16T02%3A38%3A00-05%3A00&max-results=1 http://www.joelcarroll.com/topaz/page-four/ http://www.yoshcomic.com/latest.php?i=20101201 http://agirlandherfed.com/1.833.html http://www.casualvillain.com/Unsounded/comic/ch02/ch02_27.html http://undertow.dreamshards.org/3/u3_13.html http://www.sisterclaire.com/comic/chapter-6-comic/chapter-6-the-trials/ http://sarahzero.com/sz_0588.html http://www.colourofivy.com/annyseed_webcomic8.htm http://flakypastry.runningwithpencils.com/comic.php?strip_id=326 */