Gelbooru KonaStyle

Change gelbooru.com theme to darker, similar to konachan style. Added filtration image options, images with blacklist tags will be remove from search result. Also adden upvote&downvote button to preview page. Added buttons to hide submenu and red message in header.

  1. // ==UserScript==
  2. // @name Gelbooru KonaStyle
  3. // @namespace http://Aestellar.homepage/
  4. // @version 0.15
  5. // @description Change gelbooru.com theme to darker, similar to konachan style. Added filtration image options, images with blacklist tags will be remove from search result. Also adden upvote&downvote button to preview page. Added buttons to hide submenu and red message in header.
  6. // @author Aestellar
  7. // @include *://gelbooru.com/*
  8. // @resource gelbooruCss1 https://userstyles.org/styles/111063/gelbooru-konastyle-test.css
  9. // @grant GM_getResourceText
  10. // @grant GM_addStyle
  11.  
  12. // @run-at document-start
  13.  
  14. // ==/UserScript==
  15. /*jshint multistr: true */
  16. (function(){
  17. var win = window;
  18. var ls = localStorage;
  19. var css = GM_getResourceText ("gelbooruCss1");
  20.  
  21. var searcher;
  22. if(!win){
  23. console.log(win + "Failed to load window object");
  24. return;
  25. }
  26.  
  27. if(win.self != win.top){
  28. return;
  29. }
  30.  
  31.  
  32. addStyle(css);
  33. document.addEventListener("DOMContentLoaded",updateUI, false);
  34.  
  35. function loadPrereq(){
  36. var hrefVar = win.location.href;
  37. if(/(htt[ps]:\/\/gelbooru\.com[\/]*)$/.test(hrefVar)){
  38. document.body.className = 'main-page';
  39. }
  40. var fontAwesomeLoader = document.createElement('div');
  41. //Font awesome support Don't work with @resource
  42. fontAwesomeLoader.innerHTML = '<link rel="stylesheet" type="text/css" media="screen" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.css" />';
  43. fontAwesomeLoader = fontAwesomeLoader.children[0];
  44. document.head.appendChild(fontAwesomeLoader);
  45. }
  46.  
  47.  
  48. function updateUI(){
  49. loadPrereq();
  50. checkLastVisit();
  51. searcher = new SearchWidget();
  52. searcher.init();
  53. createSettingsWindow();
  54. updateNav();
  55. updateThumbs();
  56. }
  57.  
  58. function SearchWidget (){
  59. this.searchElt = undefined;
  60. this.searchForm = undefined;
  61. this.filtersList = [];
  62. var self = this;
  63. this.submit = function(e){
  64. var text = self.searchElt.value;
  65. text = self.applySearchFilters(text);
  66. self.searchElt.value = text;
  67. };
  68.  
  69. this.applySearchFilters = function(text){
  70. for (var i = 0; i < this.filtersList.length; i++) {
  71. text = this.filtersList[i](text);
  72. }
  73. return text;
  74. };
  75.  
  76. this.init = function(){
  77. this.searchElt = qS('#stags')||qS('#tags');
  78. if (!this.searchElt) {
  79. throw new Error('Search field not found');
  80. }
  81. this._createFilters();
  82. this.searchForm = qS('.sidebar3 form');
  83. if (!this.searchForm) {
  84. throw new Error('Search form not found');
  85. }
  86. this.searchForm.onsubmit = this.submit;
  87. };
  88. this._createFilters = function(){
  89. var newImageFilter = function(text){
  90. if (ls.getItem('onlyNewSearch')==='true') {
  91. if (!!getLastImageId()) {
  92. var newId = ' id:>' + getLastImageId() + ' ';
  93. if (text.indexOf(newId)===-1) {
  94. text+=newId;
  95. }
  96. }
  97. }
  98. return text;
  99. };
  100. this.filtersList.push(newImageFilter);
  101. };
  102. }
  103.  
  104. function updateThumbs(){
  105. var c = qS('.thumb');
  106. if (!c){
  107. return;
  108. }
  109.  
  110. var thumbsContainer = c.parentNode;
  111. c = thumbsContainer.parentNode;
  112. processThumbs(thumbsContainer);
  113.  
  114. observeDOM(c, function(e){
  115. var temp =e.forEach;
  116. if (!!temp) {
  117. e.forEach(function(elt){
  118. var test;
  119. var t = elt.addedNodes;
  120. if (!!t) {
  121. t = t[0];
  122.  
  123. if (!t) {
  124. return;
  125. }
  126.  
  127. if (!t.getElementsByClassName){
  128. return;
  129. }
  130. test = t.getElementsByClassName('thumb');
  131. if (!!test.length) {
  132.  
  133. processThumbs(t);
  134. }
  135. }
  136. });
  137. }
  138. });
  139. }
  140.  
  141. function appendThumbPane(thumb){
  142. var test = makeDiv('thumb-pane');
  143. var url = getImageRefFromThumb(thumb);
  144. url = url.replace('thumbnails','images');
  145. url = url.replace('thumbnail_','');
  146. if(getTagListFromThumb(thumb).search('animated_gif')!=-1){
  147. makeRef('gif');
  148. }
  149. else if (getTagListFromThumb(thumb).search('webm')!=-1) {
  150. makeRef('webm');
  151. }
  152. else{
  153. var ext = ['png','jpeg','jpg'];
  154. for (var i = ext.length - 1; i >= 0; i--) {
  155. makeRef(ext[i]);
  156. }
  157. }
  158.  
  159. function makeRef(extension){
  160. var ref = document.createElement('a');
  161. ref.textContent = extension;
  162. var url2 = url.replace('jpg',extension);
  163. ref.setAttribute('href', url2);
  164. test.appendChild(ref);
  165. }
  166.  
  167.  
  168. var dataId = getIdFromThumb(thumb);
  169. test.setAttribute('data-id', dataId);
  170. test.setAttribute('data-voted', 'false');
  171.  
  172. var upBtn = document.createElement('span');
  173. var downBtn = document.createElement('span');
  174.  
  175. makeSimpleButton(upBtn,
  176. {name:'upBtn',
  177. glyph:'fa-thumbs-up',
  178. callback:voteUp
  179. });
  180.  
  181. makeSimpleButton(downBtn,
  182. {name:'downBtn',
  183. glyph:'fa-thumbs-down',
  184. callback:voteDown
  185. });
  186.  
  187. test.insertBefore(upBtn,test.firstChild);
  188. //test.appendChild(ref);
  189. test.appendChild(downBtn);
  190.  
  191. thumb.appendChild(test);
  192. }
  193.  
  194. function voteImage(e, vote){
  195. var parent = e.bindedElt;
  196. var pane = parent.parentNode;
  197. if (pane.getAttribute('data-voted')!=='false') {
  198. return;
  199. }
  200. var id = pane.getAttribute('data-id');
  201.  
  202. handleXHRDoc('index.php?page=post&s=vote&id='+id+'&type='+vote, function(doc){
  203. var score = doc.body.textContent;
  204. parent.textContent=score;
  205. pane.setAttribute('data-voted', 'true');
  206. });
  207. }
  208.  
  209. function voteUp(e){
  210. voteImage(e, 'up');
  211. }
  212.  
  213. function voteDown(e){
  214. voteImage(e, 'down');
  215. }
  216.  
  217.  
  218. function isImageFiltering(){
  219. return ls.getItem('disableImageFiltering')==='false';
  220. }
  221.  
  222. function isPreviewPaneEnabled(){
  223. return ls.getItem('disablePreviewPane')==='false';
  224. }
  225.  
  226.  
  227. function processThumbs(container){
  228. if (!!container) {
  229. for (var i = 0; i <container.children.length; i++) {
  230. var loop = container.children[i];
  231.  
  232. if(filterThumb(loop)){
  233. continue;
  234. }
  235. if (isPreviewPaneEnabled()) {
  236. appendThumbPane(loop);
  237. }
  238. }
  239. }
  240. }
  241.  
  242. function increaseFilterCount(){
  243. var countElt = qS('#filterCount');
  244. var count = countElt.textContent;
  245. count = parseInt(count);
  246. count+=1;
  247. countElt.textContent=count;
  248. }
  249.  
  250. function filterThumb(thumb){
  251. if (!isImageFiltering()) {
  252. return false;
  253. }
  254.  
  255. var thumbTags = getTagListFromThumb(thumb);
  256. if (!!thumbTags) {
  257. if (isBannedThumb(thumbTags)) {
  258. hide(thumb);
  259. increaseFilterCount();
  260. return true;
  261. }
  262. }
  263. return false;
  264. }
  265.  
  266. function isBannedThumb(thumbList){
  267. var bannedList = getBannedList();
  268. var loop;
  269.  
  270. if (!bannedList) {
  271. return false;
  272. }
  273. bannedList = bannedList.replace('\n', ' ');
  274. bannedList = bannedList.replace(/\s+/g, ' ');
  275. bannedList = bannedList.replace(/(\s+)$/g, '');
  276. bannedList = bannedList.replace(/^(\s+)/g, '');
  277. bannedList = bannedList.split(' ');
  278. for (var i = bannedList.length - 1; i >= 0; i--) {
  279. loop = bannedList[i];
  280. loop = new RegExp('\\b'+ loop + '\\b');
  281. if (thumbList.search(loop)!=-1) {
  282. return true;
  283. }
  284. }
  285. return false;
  286. }
  287.  
  288. function getIdFromThumb(thumb){
  289. var id = thumb.getAttribute('id');
  290. if (!!id) {
  291. id = id.replace('s', '');
  292. }
  293. return id;
  294. }
  295.  
  296. function getImageRefFromThumb(thumb){
  297. var img = thumb.getElementsByTagName('img')[0];
  298. if (!!img) {
  299. return img.getAttribute('src');
  300. }
  301. }
  302.  
  303. function getTagListFromThumb(thumb){
  304. if (!thumb) {
  305. return;
  306. }
  307. var thumbImg = thumb.getElementsByClassName('preview')[0];
  308. if (!!thumbImg) {
  309. return thumbImg.getAttribute('alt');
  310. }
  311. }
  312.  
  313. function getBannedList(){
  314. var bannedList = ls.getItem('bannedTagsList');
  315. return bannedList;
  316. }
  317. function getFavoritesTagsList(){
  318. var favoritesList = ls.getItem('favoritesTagsList');
  319. return favoritesList;
  320. }
  321.  
  322.  
  323. function updateNav() {
  324. var navBar = qS('.flat-list');
  325. var settingsBtn = document.createElement("li");
  326. var navBtn = document.createElement("li");
  327. var advNav = document.createElement("li");
  328. navBar.insertBefore(settingsBtn, navBar.firstChild);
  329. navBar.insertBefore(advNav, navBar.firstChild);
  330. navBar.insertBefore(navBtn, navBar.firstChild);
  331.  
  332. var s = {name:'settingsBtn',
  333. glyph:'fa-gear',
  334. callback:showSettingsWindow};
  335.  
  336. makeUserNavBar();
  337.  
  338. var sett = {name:'navCollapse', glyphOff:'fa-minus-square-o', glyphOn:'fa-plus-square-o',
  339. callbackOff:makeToggleFunc(['.submenu', '.noticeError'], show), callbackOn:makeToggleFunc(['.submenu', '.noticeError'], hide)};
  340.  
  341. var sett2 = {name:'advNavCollapse', glyphOff:'fa-search-minus', glyphOn:'fa-search-plus',
  342. callbackOff:makeToggleFunc(['#usernavbar'], show), callbackOn:makeToggleFunc(['#usernavbar'], hide)};
  343.  
  344. makeSimpleButton(settingsBtn, s);
  345. makeToggleButton(navBtn,sett);
  346. makeToggleButton(advNav,sett2);
  347. }
  348.  
  349. function createSettingsWindow(){
  350. var mod = document.createElement('div');
  351. mod.className = 'modalDialog';
  352. mod.innerHTML = '<div class = modalDialogBox>\
  353. <span title="Close" class="close"></span>\
  354. </div>';
  355. document.body.appendChild(mod);
  356. mod.addEventListener('click',hideModalWindow,false);
  357.  
  358. var close = qS('.modalDialog .close');
  359.  
  360. makeSimpleButton(close,
  361. {name:'settingsBtn',
  362. glyph:'fa-times',
  363. callback:hideSettingsWindow
  364. });
  365.  
  366. var dialog = qS('.modalDialogBox');
  367. dialog.appendChild(makeSettingsInner());
  368.  
  369. }
  370.  
  371. function makeSettingsInner(){
  372. var div = document.createElement('div');
  373. div.innerHTML = '<span class="modalName">Settings</span>';
  374.  
  375. var settTab = new TabbedPane();
  376. div.appendChild(settTab.tabbedPane);
  377.  
  378. var mainSetting = makeDiv('main-settings');
  379.  
  380. var disableFilteringRule = makeDiv('settings-rule');
  381. disableFilteringRule.textContent = 'Disable image filtering: ';
  382. disableFilteringRule.appendChild(makeCheckBox('disableImageFiltering'));
  383. mainSetting.appendChild(disableFilteringRule);
  384.  
  385.  
  386. var disableThumbPane = makeDiv('settings-rule');
  387. disableThumbPane.textContent = 'Don\' show preview panel: ';
  388. disableThumbPane.appendChild(makeCheckBox('disablePreviewPane'));
  389. mainSetting.appendChild(disableThumbPane);
  390.  
  391. var bannedTagsTab = document.createElement('textarea');
  392. bannedTagsTab.className = 'bannedList';
  393. bannedTagsTab.value = getBannedList();
  394. bannedTagsTab.addEventListener('input',function(e){
  395. ls.setItem('bannedTagsList',e.target.value);
  396. },false);
  397.  
  398. var favoritesTagsTab = document.createElement('textarea');
  399. favoritesTagsTab.className = 'bannedList';
  400. favoritesTagsTab.value = getFavoritesTagsList();
  401. favoritesTagsTab.addEventListener('input',function(e){
  402. ls.setItem('favoritesTagsList',e.target.value);
  403. },false);
  404.  
  405.  
  406. settTab.addTab('sett1', 'Settings', mainSetting);
  407. settTab.addTab('sett2','Banned tags', bannedTagsTab);
  408. //settTab.addTab('sett3','Favorites tags', favoritesTagsTab);
  409. //console.log(settTab);
  410.  
  411. // var iTest = makeDiv('');
  412. // iTest.innerHTML = '<img src="http://i.nhentai.net/galleries/795920/cover.jpg">';
  413. // settTab.addTab('sett3','imageTest', iTest);
  414. settTab.selectDefault();
  415.  
  416.  
  417. return div;
  418. }
  419.  
  420. function showSettingsWindow(e){
  421. var mod = qS('.modalDialog');
  422. mod.classList.add('modalActive');
  423. }
  424.  
  425. function hideModalWindow(e){
  426. var mod = qS('.modalDialog');
  427. if (e && (e.target!== mod)) {
  428. return;
  429. }
  430. hideSettingsWindow(e);
  431. }
  432.  
  433. function hideSettingsWindow(e){
  434. var mod = qS('.modalDialog');
  435. mod.classList.remove('modalActive');
  436. }
  437.  
  438.  
  439. function makeUserNavBar(){
  440. var userBar = document.createElement('ul');
  441. userBar.className = 'flat-list';
  442. userBar.setAttribute('id', 'usernavbar');
  443. var navBar = qS('.submenu');
  444. var navParent = navBar.parentNode;
  445. navParent.insertBefore(userBar,navBar.nextSibling);
  446.  
  447. makeFitImageBtn(userBar);
  448. makeAdvSearchPane(userBar);
  449.  
  450. }
  451.  
  452. function makeToggleFunc(sel,action){
  453.  
  454. var activeFoo = function(){
  455. for (var i = sel.length - 1; i >= 0; i--) {
  456. action(qS(sel[i]));
  457. }
  458. };
  459. return activeFoo;
  460. }
  461.  
  462. function makeFitImageBtn(userBar){
  463. var fitBtn = document.createElement("li");
  464. userBar.appendChild(fitBtn);
  465. fitBtn.title = 'Autofit image or webm to page width';
  466. var imageFit = makeToggleButton(fitBtn, {name:'fitImage',
  467. glyphOff:'fa fa-compress',
  468. glyphOn:'fa fa-expand',
  469. callbackOff:fitImage,
  470. callbackOn:fitImage});
  471. function fitImage(){
  472. var img = qS('#image')||qS('#gelcomVideoPlayer');
  473. if (img === undefined) {
  474. return;
  475. }
  476.  
  477. img.removeAttribute('width');
  478. img.removeAttribute('height');
  479.  
  480. if ((localStorage.getItem('fitImage')==='true')) {
  481. img.style.maxWidth = '100%';
  482. }
  483.  
  484. else{
  485. img.style.maxWidth = '';
  486. }
  487.  
  488. if(!!img){
  489. img.addEventListener('load', fitImage, false);
  490. }
  491. }
  492. }
  493.  
  494. function makeAdvSearchPane(userBar){
  495. var advSearch = document.createElement('div');
  496. advSearch.innerHTML = '<div id = "adv-search">\
  497. <li><span>Advanced Search: </span>\
  498. <span id = "only-new">Only new images </span></li>\
  499. <li><span>Filtered images: <span id="filterCount">0</span></span></li>\
  500. </div>';
  501. advSearch = advSearch.firstChild;
  502. userBar.appendChild(advSearch);
  503. var onlyNew = document.getElementById('only-new');
  504.  
  505. makeToggleButton(onlyNew, {name:'onlyNewSearch',
  506. glyphOff:'fa-square-o',
  507. glyphOn:'fa-check-square-o'
  508. });
  509. return advSearch;
  510. }
  511.  
  512. function makeCheckBox(rname){
  513. var box = makeSpan('checkbox-span');
  514. makeToggleButton(box,
  515. {name:rname,
  516. glyphOff:'fa-square-o',
  517. glyphOn:'fa-check-square-o'
  518. });
  519. return box;
  520. }
  521.  
  522. function makeToggleButton(elem, settings){
  523. var btn = new ButtonToggle(settings);
  524. btn.bindElement(elem);
  525. btn.load();
  526. elem.addEventListener('click', btn.handlerClick, false);
  527. return btn;
  528. }
  529.  
  530. function makeSimpleButton(elem, settings){
  531. var btn = new ButtonSimple(settings);
  532. btn.bindElement(elem);
  533. elem.addEventListener('click', btn.handlerClick, false);
  534. return btn;
  535. }
  536.  
  537.  
  538. function ButtonSimple(settings){
  539. var self = this;
  540. var modGliph = 'fa-lg';
  541. this.name = settings.name;
  542.  
  543. this.glyphElt = document.createElement('i');
  544. this.active = false;
  545. this.bindedElt = null;
  546. this.callback = settings.callback;
  547. this.bindElement = function (elem) {
  548. self.bindedElt = elem;
  549. if (self.bindedElt.length > 0) {
  550. elem.insertChildBefore(self.glyphElt, elem.FirstChild);
  551. }
  552. else {
  553. elem.appendChild(self.glyphElt);
  554. }
  555. };
  556. this.glyph = 'fa ' + settings.glyph + ' ' + modGliph;
  557. self.glyphElt.className = self.glyph;
  558.  
  559. this.handlerClick = function (e) {
  560. self.callback(self);
  561. };
  562. }
  563.  
  564. function ButtonToggle(settings) {
  565. var self = this;
  566.  
  567. var modGliph = 'fa-lg';
  568. this.name = settings.name;
  569.  
  570. this.active = false;
  571. this.bindedElt = null;
  572. this.glyphElt = document.createElement('i');
  573. this.bindElement = function (elem) {
  574. self.bindedElt = elem;
  575. if (self.bindedElt.length > 0) {
  576. elem.insertChildBefore(self.glyphElt, elem.FirstChild);
  577. }
  578. else {
  579. elem.appendChild(self.glyphElt);
  580. }
  581. };
  582.  
  583. this.glyphOn = 'fa ' + settings.glyphOn + ' ' + modGliph;
  584. this.glyphOff = 'fa ' + settings.glyphOff + ' ' + modGliph;
  585. this.callbackOn = settings.callbackOn;
  586. this.callbackOff = settings.callbackOff;
  587. this.save = function () {
  588. localStorage.setItem(self.name, self.active);
  589. };
  590. this.load = function () {
  591. var t = localStorage.getItem(self.name);
  592. if (t === 'true') {
  593. self.setActive(true);
  594. }
  595. else {
  596. self.setActive(false);
  597. }
  598. };
  599. this.handlerClick = function (e) {
  600. if (self.active) {
  601. self.setActive(false);
  602. }
  603.  
  604. else {
  605. self.setActive(true);
  606. }
  607. };
  608.  
  609. this.setActive = function (val) {
  610. val = !!val;
  611. self.active = val;
  612. self.save(val);
  613.  
  614. if (val) {
  615. if (!!self.bindedElt) {
  616. self.bindedElt.classList.add('activeBtn');
  617. self.glyphElt.className = self.glyphOn;
  618. }
  619.  
  620. if (!!self.callbackOn) {
  621. self.callbackOn(self);
  622. }
  623. }
  624.  
  625. else {
  626. if (!!self.bindedElt) {
  627. self.bindedElt.classList.remove('activeBtn');
  628. self.glyphElt.className = self.glyphOff;
  629. }
  630.  
  631. if (!!self.callbackOff) {
  632. self.callbackOff(self);
  633. }
  634. }
  635. };
  636. }
  637.  
  638.  
  639. // LastVisit functions
  640. function checkLastVisit(){
  641. var timer = 7200000;
  642. var lastVisit = parseInt(ls.getItem('lastVisit'));
  643. var prevVisit = parseInt(ls.getItem('preLastVisit'));
  644.  
  645. var currentVisit = new Date().valueOf();
  646. if ((!lastVisit)||(!prevVisit)) {
  647. updateLastVisit();
  648. }
  649. if ((lastVisit + timer) < currentVisit) {
  650. updateLastVisit();
  651. }
  652. }
  653.  
  654. function updateLastVisit(){
  655. var posts = 'http://gelbooru.com/index.php?page=post&s=list&tags=all';
  656. handleXHRDoc(posts, function(doc){
  657. var lastIdElt = doc.getElementsByClassName('thumb')[0];
  658. var lastID = lastIdElt.getAttribute('id');
  659. lastID = lastID.replace('s', '');
  660.  
  661. if (!!ls.getItem('lastVisit')) {
  662. ls.setItem('preLastVisit',ls.getItem('lastVisit'));
  663. }
  664. else{
  665. ls.setItem('preLastVisit',new Date().valueOf());
  666. }
  667. if (ls.getItem('lastImageId')) {
  668. ls.setItem('preImageId',ls.getItem('lastImageId'));
  669. }
  670. else{
  671. ls.setItem('preImageId',lastID);
  672. }
  673.  
  674. localStorage.setItem('lastVisit',new Date().valueOf());
  675. localStorage.setItem('lastImageId', lastID);
  676. });
  677. }
  678.  
  679. function getLastImageId(){
  680. var t = localStorage.getItem('preImageId');
  681. return parseInt(t);
  682. }
  683.  
  684. })();
  685.  
  686. function handleXHRDoc(reqString, callback){
  687. var doc = document.implementation.createHTMLDocument("example");
  688.  
  689. var xmlhttp = new XMLHttpRequest();
  690. xmlhttp.open('GET', reqString, true);
  691. xmlhttp.send(null);
  692. xmlhttp.onreadystatechange = handle;
  693.  
  694. function handle(){
  695. if (xmlhttp.readyState == 4) {
  696. if(xmlhttp.status == 200) {
  697. doc.documentElement.innerHTML = xmlhttp.responseText;
  698. console.log(doc);
  699. callback(doc);
  700. }
  701.  
  702. else{
  703. console.log('Error xhr of ' + reqString);
  704. }
  705. }
  706. }
  707. }
  708.  
  709.  
  710. //from http://stackoverflow.com/questions/2246901/how-can-i-use-jquery-in-greasemonkey-scripts-in-google-chrome
  711. function load(a, b, c) {
  712. var d;
  713. d = document.createElement("script"), d.setAttribute("src", a), b !== null && d.addEventListener("load", b), c !== null && d.addEventListener("error", c), document.body.appendChild(d);
  714. return d;
  715. }
  716. function execute(a) {
  717. var b, c;
  718. typeof a == "function" ? b = "(" + a + ")();" : b = a, c = document.createElement("script"), c.textContent = b, document.body.appendChild(c);
  719. return c;
  720. }
  721. function loadAndExecute(a, b) {
  722. return load(a, function () {
  723. return execute(b);
  724. });
  725. }
  726. //
  727. function qS(selector){
  728. return document.querySelectorAll(selector)[0];
  729. }
  730.  
  731. function hide(elt){
  732. if (!!elt) {
  733. elt.style.display = 'none';
  734. }
  735. else{
  736. console.log('Not found' + elt );
  737. }
  738.  
  739. }
  740. function show(elt){
  741. if (!!elt) {
  742. elt.style.display = '';
  743. }
  744. else{
  745. console.log('Not found' + elt );
  746. }
  747.  
  748. }
  749.  
  750. function removeAllChild(elem){
  751. while (elem.hasChildNodes()) {
  752. elem.removeChild(elem.lastChild);
  753. }
  754. }
  755.  
  756. function hasClass(elem, name) {
  757. if (!!elem) {
  758. if (!!elem.classList) {
  759. if (elem.classList.contains(name)) {
  760. return true;
  761. }
  762. }
  763. }
  764. return false;
  765. }
  766.  
  767. function addStyle(css){
  768. if (typeof GM_addStyle != "undefined") {
  769. GM_addStyle(css);
  770. } else if (typeof PRO_addStyle != "undefined") {
  771. PRO_addStyle(css);
  772. } else if (typeof addStyle != "undefined") {
  773. addStyle(css);
  774. } else {
  775. var node = document.createElement("style");
  776. node.type = "text/css";
  777. node.appendChild(document.createTextNode(css));
  778. var heads = document.getElementsByTagName("head");
  779. if (heads.length > 0) {
  780. heads[0].appendChild(node);
  781. } else {
  782. // no head yet, stick it whereever
  783. document.documentElement.appendChild(node);
  784. }
  785. }
  786. }
  787.  
  788.  
  789. function applyCSSRulesFromJS(){
  790. var style = document.createElement("style");
  791. style.appendChild(document.createTextNode(getCSSText()));
  792.  
  793. // Add the <style> element to the page
  794. document.head.appendChild(style);
  795.  
  796. return style.sheet;
  797. }
  798.  
  799. function makeDiv(className){
  800. var div = document.createElement('div');
  801. div.className = className;
  802. return div;
  803. }
  804.  
  805. function makeSpan(className){
  806. var div = document.createElement('span');
  807. div.className = className;
  808. return div;
  809. }
  810.  
  811. function TabbedPane (){
  812. var self = this;
  813. var tabbedPane = makeDiv("tabbed-Pane");
  814. var navPane = makeDiv("nav-Pane");
  815. var contentPane = makeDiv("content-Pane");
  816. tabbedPane.appendChild(navPane);
  817. tabbedPane.appendChild(contentPane);
  818. this.tabbedPane = tabbedPane;
  819. this.navPane = navPane;
  820. this.navMap= {};
  821. this.contentPane = contentPane;
  822. this.addTab = function(realName,visibleName,content){
  823. var head = makeDiv('tab-Head');
  824. head.textContent = visibleName;
  825. var tab = new TabPane(self, realName, head, content);
  826. self.navMap[realName]= tab;
  827. self.navPane.appendChild(head);
  828. head.addEventListener('click', tab.clickHandler, false);
  829. };
  830. this.selectTab = function(tab){
  831. var loopTab;
  832.  
  833. for (var key in self.navMap) {
  834. if (self.navMap.hasOwnProperty(key)){
  835. loopTab = self.navMap[key];
  836. loopTab.setSelected(false);
  837. }
  838. }
  839.  
  840. removeAllChild(self.contentPane);
  841. tab.setSelected(true);
  842. self.contentPane.appendChild(tab.content);
  843. };
  844. this.selectDefault = function(){
  845. for (var key in self.navMap) {
  846. if (self.navMap.hasOwnProperty(key)){
  847. self.navMap[key].clickHandler();
  848. break;
  849. }
  850. }
  851. };
  852. }
  853.  
  854. function TabPane(master,name,head,content){
  855. var self = this;
  856. this.name = name;
  857. this.masterPane = master;
  858. this.head = head;
  859. this.content = content;
  860. this.selected = false;
  861. this.setSelected = function(val){
  862. if (!!val) {
  863. self.head.classList.add('activeTab');
  864. self.selected = true;
  865. }
  866. else{
  867. self.head.classList.remove('activeTab');
  868. self.selected = false;
  869. }
  870. };
  871. this.clickHandler = function(e){
  872. self.setSelected(true);
  873. master.selectTab(self);
  874. };
  875.  
  876. }
  877.  
  878. var observeDOM = (function(){
  879. var MutationObserver = window.MutationObserver;
  880.  
  881. return function(obj, callback){
  882. // define a new observer
  883. var obs = new MutationObserver(function(mutations, observer){
  884. if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
  885. //console.log(obj)
  886. callback(mutations);
  887. });
  888. // have the observer observe foo for changes in children
  889. obs.observe( obj, { childList:true, subtree:false });
  890. }
  891. })();