Skip to content

Instantly share code, notes, and snippets.

@binux
Created December 20, 2013 11:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save binux/8053788 to your computer and use it in GitHub Desktop.
Save binux/8053788 to your computer and use it in GitHub Desktop.
// vim: set et sw=2 ts=2 sts=2 ff=unix fenc=utf8:
// Author: Binux<i@binux.me>
// http://binux.me
// Created on 2013-09-17 10:53:19
(function() {
window.console = window.console || {};
window.console.log = window.console.log || function() {};
var _ = {};
_.debug = false;
_.start_time = new Date();
_.once = function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
};
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;
return function() {
context = this;
args = arguments;
timestamp = new Date();
var later = function() {
var last = (new Date()) - timestamp;
if (last < wait) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) result = func.apply(context, args);
}
};
var callNow = immediate && !timeout;
if (!timeout) {
timeout = setTimeout(later, wait);
}
if (callNow) result = func.apply(context, args);
return result;
};
};
var breaker = 'break';
var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj === null) return;
if (obj.length === +obj.length) {
for (var i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
var keys = _.keys(obj);
for (var i = 0, length = keys.length; i < length; i++) {
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
};
_.toArray = function(list) {
var result = [];
_.each(list, function(e) {
result.push(e);
});
return result;
};
var serializer = new XMLSerializer();
_.toString = function(data) {
if (typeof data === 'string')
return data;
//else if (data instanceof Document)
//return data.querySelector('html').outerHTML;
else if (data instanceof Node)
return serializer.serializeToString(data);
else
try {
return JSON.stringify(data);
} catch(e) {
return String(data);
}
};
_.save = function(key, value) {
if (typeof SunflowerService != 'undefined')
SunflowerService(2, {key: _.toString(key), value: _.toString(value)});
else
console.log((new Date()), (new Date())-this.start_time, key, value);
};
_.log = function(msg) {
if (typeof SunflowerService != 'undefined')
SunflowerService(1, _.toString(msg));
else
console.log((new Date()), (new Date())-this.start_time, msg);
};
_.sunflower_stop = function() {
if (typeof SunflowerService != 'undefined')
SunflowerService(7, 'stop!');
};
_._remote_log = function(msg, elem) {
if (!_.debug) return;
msg = ''+(new Date())+' '+((new Date())-this.start_time)+' '+_.toString(msg);
var e = document.createElement('SPAN');
e.innerHTML = msg;
document.body.appendChild(e);
};
_.remote_log = function(msg, elem) {
if (!_.debug) return;
var s = document.createElement('SCRIPT');
s.src = 'http://__REMOTE_ADDR__/?log=' + encodeURIComponent(''+(new Date())+' '+((new Date())-this.start_time)+' '+_.toString(msg));
if (s.src.indexOf('_REMOTE_ADDR_') != -1) {
console.log((new Date()), (new Date())-this.start_time, msg, elem);
} else {
document.body.appendChild(s);
}
};
_.isdescendant = function(parent, child) {
if (parent == child) return true;
var node = child.parentNode;
while (node !== null) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
};
_.keydown = function(charcode, elm) {
var evt = document.createEvent("KeyboardEvent");
evt[evt.initKeyEvent?'initKeyEvent':'initKeyboardEvent']("keydown", true, true, window,
0, 0, 0, 0,
charcode, 0);
(elm || document.body).dispatchEvent(evt);
};
_.click = function(elem) {
var top = 0, left = 0, _elem = elem;
do {
if ( !isNaN( _elem.offsetLeft) ) left += _elem.offsetLeft;
if ( !isNaN( _elem.offsetTop) ) top += _elem.offsetTop;
} while( _elem = _elem.offsetParent );
top += elem.offsetHeight*0.75;
left += elem.offsetWidth*0.75;
var evt = document.createEvent("MouseEvent");
evt.initMouseEvent("click", true, true, window,
1, left, top, left, top,
0, 0, 0, 0,
0, null);
elem.dispatchEvent(evt);
};
_.fire = function(event, data) {
var evt = document.createEvent("Events");
evt.initEvent(event, true, true);
evt.data = data;
document.dispatchEvent(evt);
};
_.onload = function(func) {
if (document.readyState === "complete") {
func();
} else {
window.addEventListener('load', func);
}
};
_.dump_tree = function(changed_elements) {
var elements = [];
_.each(changed_elements, function(e) {
while(e) {
elements.push(e);
e = e.parentNode;
}
});
var _document = document.cloneNode(false);
function build(root, _root) {
_.each(root.childNodes, function(e) {
if (changed_elements.indexOf(e) != -1) {
_root.appendChild(_document.importNode(e, true));
} else if (elements.indexOf(e) != -1) {
var _e = _document.importNode(e, false);
build(e, _e);
_root.appendChild(_e);
}
});
}
build(document, _document);
return _document;
};
_.ec_xpath2selector = function(ec_xpath) {
var result = [];
_.each(ec_xpath.split('/').reverse(), function(e) {
result.push(e.replace(' ', '.', 'g'));
});
return result.join('>').replace(/^>/, '');
};
var ballowed_tag = ['ul', 'li', 'a', 'ol', 'table', 'tr', 'dd', 'dt', 'dl', 'h1', 'h2', 'h3', 'h4',
'b', 'i', 'strong', 'em', 'img', 'code', 'small'];
_.get_selector = function(element, need_tagName) {
need_tagName = need_tagName === undefined ? true : false;
var _getSelector = function(element, need_tagName) {
var result = '';
if (need_tagName) {
result += element.tagName;
} else if (ballowed_tag.indexOf(element.tagName.toLowerCase()) != -1) {
result += element.tagName;
}
if (element.getAttribute('id')) {
return result+'#'+element.getAttribute('id');
} else if (element.classList.length > 0) {
for(var i=0; i<element.classList.length; i++) {
result += '.'+element.classList[i];
}
}
return result;
};
var result = [];
result.push(_getSelector(element, need_tagName));
while( element = element.parentElement ) {
var selector = _getSelector(element, need_tagName);
if (selector !== '')
result.push(selector);
else
result.push('*');
}
result.reverse();
return result.join('>');
};
var parsers = [];
//https://code.google.com/p/visual-event-oex/source/browse/trunk/includes/visual-event.js
(function() {
parsers.push( function () {
var
elements = [], n,
all = document.getElementsByTagName('*'),
types = [ 'click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover',
'mouseup', 'change', 'focus', 'blur', 'scroll', 'select', 'submit', 'keydown', 'keypress',
'keyup', 'load', 'unload' ],
i, iLen, j, jLen = types.length;
for (var i=0, iLen=all.length ; i<iLen ; i++ ) {
for ( j=0 ; j<jLen ; j++ ) {
if ( typeof all[i]['on'+types[j]] == 'function' ) {
elements.push( {
"node": all[i],
"listeners": [ {
"type": types[j],
"func": all[i]['on'+types[j]].toString(),
"removed": false,
"source": 'DOM 0 event'
} ]
} );
}
}
}
return elements;
} );
parsers.push( function() {
var elements = [];
all = document.getElementsByTagName('a');
_.each(all, function(e) {
if ((e.getAttribute('href') || "").match(/^(javascript|#)/i)) {
elements.push( {
"node": e,
"listeners": [ {
"type": 'click',
"func": e.getAttribute('href'),
"removed": false,
"source": 'href script'
} ]
} );
}
});
return elements;
} );
parsers.push( function () {
if ( !jQuery || jQuery.fn.live != 'undefined' ||
typeof jQuery.data == 'undefined' ||
typeof jQuery.data(document, "events") == 'undefined' ||
typeof jQuery.data(document, "events").live == 'undefined' )
{
return [];
}
var elements = [];
var cache = jQuery.cache;
jQuery.each( jQuery.data(document, "events").live || [], function(i, fn) {
var event = fn.type.split('.');
event = event[0];
var selector = fn.data;
$(selector).each( function(i) {
elements.push( {
node: this,
listeners: []
} );
elements[elements.length - 1].listeners.push({
type: event,
func: 'Unable to obtain function from live() bound event.',
removed: false,
source: "jQuery 1.3 live"
} )
} );
} );
return elements;
} );
parsers.push( function () {
var version = jQuery.fn.jquery.substr(0,3)*1;
if ( !jQuery || version < 1.5 || version >= 1.7 ) {
return [];
}
var elements = [];
for ( j in jQuery.cache ) {
jQueryGeneric( elements, jQuery.cache[j] );
}
return elements;
} );
parsers.push( function () {
var version = jQuery.fn.jquery.substr(0,3)*1;
if ( !jQuery || version < 1.4 ) {
return [];
}
var elements = [];
jQueryGeneric( elements, jQuery.cache );
return elements;
} );
function jQueryGeneric (elements, cache)
{
for ( i in cache ) {
if ( typeof cache[i].events == 'object' ) {
var eventAttachedNode = cache[i].handle.elem;
var func;
for ( type in cache[i].events ) {
/* Ignore live event object - live events are listed as normal events as well */
if ( type == 'live' ) {
continue;
}
var oEvents = cache[i].events[type];
for ( j in oEvents ) {
var aNodes = [];
var sjQuery = "jQuery "+jQuery.fn.jquery;
if ( typeof oEvents[j].selector != 'undefined' && oEvents[j].selector !== null ) {
aNodes = $(oEvents[j].selector, cache[i].handle.elem);
sjQuery += " (live event)";
}
else {
aNodes.push( eventAttachedNode );
}
for ( var k=0, kLen=aNodes.length ; k<kLen ; k++ ) {
elements.push( {
"node": aNodes[k],
"listeners": []
} );
if ( typeof oEvents[j].origHandler != 'undefined' ) {
func = oEvents[j].origHandler.toString();
}
else if ( typeof oEvents[j].handler != 'undefined' ) {
func = oEvents[j].handler.toString();
}
else {
func = oEvents[j].toString();
}
/* We use jQuery for the Visual Event events... don't really want to display them */
if ( oEvents[j] && oEvents[j].namespace != "VisualEvent" && func != "0" )
{
elements[ elements.length-1 ].listeners.push( {
"type": type,
"func": func,
"removed": false,
"source": sjQuery
} );
}
}
}
}
}
}
};
parsers.push( function () {
if ( typeof jsBase == 'undefined' ) {
return [];
}
var elements = [];
var a = jsBase.aEventCache;
var i, iLen;
for (var i=0, iLen=a.length ; i<iLen ; i++ )
{
elements.push( {
"node": a[i].nElement,
"listeners": [ {
"type": a[i].type,
"func": a[i].fn.toString(),
"removed": false,
"source": 'jsBase'
} ]
} );
}
return elements;
} );
parsers.push( function () {
if ( typeof MooTools == 'undefined' ) {
return [];
}
var elements = [];
var all = document.getElementsByTagName('*');
var i, iLen;
var events, mooEvent;
for (var i=0, iLen=all.length ; i<iLen ; i++ ) {
events = all[i].retrieve('events', {});
if ( !$.isEmptyObject( events ) ) {
elements.push( {
"node": all[i],
"listeners": []
} );
for ( mooEvent in events ) {
elements[ elements.length-1 ].listeners.push( {
"type": mooEvent,
"func": events[mooEvent].keys.toString(),
"removed": false,
"source": 'MooTools'
} );
}
}
}
return elements;
} );
parsers.push( function () {
if ( typeof Prototype == 'undefined' ) {
return [];
}
var elements = [];
var all = document.getElementsByTagName('*');
var i, iLen;
var eventType;
for (var i=0, iLen=all.length ; i<iLen ; i++ ) {
if ( typeof all[i]._prototypeEventID != 'undefined' ) {
elements.push( {
"node": all[i],
"listeners": []
} );
for ( eventType in Event.cache[ all[i]._prototypeEventID ] ) {
elements[ elements.length-1 ].listeners.push( {
"type": eventType,
"func": Event.cache[ all[i]._prototypeEventID ][eventType][0].handler.toString(),
"removed": false,
"source": 'Prototype'
} );
}
}
}
return elements;
} );
parsers.push( function () {
if ( typeof YAHOO == 'undefined' || typeof YAHOO.util == 'undefined' ||
typeof YAHOO.util.Event == 'undefined' )
{
return [];
}
/*
* Since the YUI cache is a private variable - we need to use the getListeners function on
* all nodes in the document
*/
var all = document.getElementsByTagName('*');
var i, iLen, j, jLen;
var elements = [], events;
for (var i=0, iLen=all.length ; i<iLen ; i++ )
{
events = YAHOO.util.Event.getListeners( all[i] );
if ( events != null && events.length != 0 )
{
elements.push( {
"node": events[0].scope,
"listeners": []
} );
for ( j=0, jLen=events.length ; j<jLen ; j++ )
{
elements[ elements.length-1 ].listeners.push( {
"type": events[j].type,
"func": events[j].fn.toString(),
"removed": false,
"source": 'YUI 2'
} );
}
}
}
return elements;
} );
})();
_.event_elements = function() {
var elements = [], i, iLen;
for (i=0, iLen=parsers.length ; i<iLen ; i++ ) {
try {
libraryListeners = parsers[i]();
elements = elements.concat( libraryListeners );
} catch (e) { }
}
var _elements = [];
_.each(elements, function(elem) {
if (!elem.node) return;
var found = false;
_.each(_elements, function(_elem) {
if (_elem.node == elem.node) {
found = true;
_elem.listeners = _elem.listeners.concat( elem.listeners );
}
});
if (!found) {
_elements.push(elem);
}
});
return elements;
};
_.record_dom_change = function() {
var result = {};
var changed_elements = [];
var bind_elements = [], observers = [];
result.changed_elements = changed_elements;
result.changed = false
result.onchange = [];
result.addListener = function(callback) {
this.onchange.push(callback);
};
function oninsert(ev) {
if (ev.target.nodeName == 'SCRIPT') return;
result.changed = true;
changed_elements.push(ev.target);
_.each(result.onchange, function(e) {
e.call(result, ev);
});
}
function onmodified(ev) {
if ((ev.attrName || ev.attributeName) != 'src') return;
result.changed = true;
changed_elements.push(ev.target);
_.each(result.onchange, function(e) {
e.call(result, ev);
});
}
document.addEventListener('DOMNodeInserted', oninsert);
_.each(document.querySelectorAll('img'), function(img) {
if (window.MutationObserver) {
var observer = new MutationObserver(function(mutations) {
_.each(mutations, onmodified);
});
observer.observe(img, { attributes: true });
observers.push(observer);
} else {
bind_elements.push(img);
img.addEventListener('DOMAttrModified', onmodified);
}
});
result.stop = function() {
document.removeEventListener('DOMNodeInserted', oninsert);
_.each(bind_elements, function(img) {
img.removeEventListener('DOMAttrModified', onmodified);
});
_.each(observers, function(ob) {
ob.disconnect();
});
this.stoped = true;
};
return result;
};
// start here
_.onload(function() {
_.remote_log('loaded');
// event_elemts attrs
var event_elements = _.event_elements();
var event_nodes = [];
var next_re = /(下一)/i, next_id_re = /(next|right)/i, main_re = /(pic|photo|content|main|body|container|img|image|big|show|cover|show|cover|full|box|large|view|gallery)/ig;
_.each(event_elements, function(elem) {
var node = elem.node;
if (!node) return;
if (node._data) return;
node._data = {};
// is_document
if (node instanceof Document) return;// node._data.is_document = true;
if (node.tagName == 'HTML' || node.tagName == 'BODY') return;
// is_click
_.each(elem.listeners, function(listener) {
if (listener.type == 'click' || listener.type == 'focus' || listener.type.indexOf('mouse') != -1) {
node._data.is_click = true;
return breaker;
}
});
if (!node._data.is_click) return;
// is_next
if (next_id_re.test(node.getAttribute('id')) ||
next_id_re.test(node.getAttribute('class')) ||
next_re.test(node.title) ||
next_re.test(node.textContent)) {
node._data.is_next = true;
}
// main_cnt
node._data.main_cnt = (_.get_selector(node, false).match(main_re) || "").length;
event_nodes.push(node);
});
var big_imgs = [];
//_.remote_log(document.querySelectorAll('img').length);
//_.each(document.querySelectorAll('img'), function(img) {
//_.remote_log(img);
//});
_.each(document.querySelectorAll('img'), function(img) {
if (!img.src) return;
if (img.src.indexOf('logo') != -1) return;
if (img.offsetParent === null) return; // display: none
// offset_top
var _img, offset_top, offset_width, depth = 0;
for (_img=img, offset_top=0; _img; _img=_img.offsetParent) {
offset_top += _img.offsetTop;
}
if (offset_top > 1200) return;
// offset_weidth
//if (img.width || img.style.width) {
//offset_width = (img.width || img.style.width);
//}
if (offset_width === undefined) {
for (_img=img, offset_width=0; _img; _img=_img.parentElement) {
if (img.offsetWidth != _img.offsetWidth) {
offset_width = _img.offsetWidth;
break;
}
}
}
//_.remote_log(_.toString(img)+' '+offset_width);
if (offset_width < 500) return;
// depth
for (_img=img, offset_width=0; _img; _img=_img.parentElement) {
depth ++;
}
img._data = {};
img._data.depth = depth;
img._data.offset_top = offset_top;
img._data.offset_width = offset_width;
img._data.main_cnt = (_.get_selector(img, false).match(main_re) || "").length;
img._data.selector = _.get_selector(img);
img._data.parent_selector = img.parentNode ? _.get_selector(img.parentNode) : img._data.selector;
img._data.selector_cnt = document.querySelectorAll(img._data.selector).length;
big_imgs.push(img);
});
big_imgs = big_imgs.sort(function(a, b) {
if (a._data.selector_cnt != b._data.selector_cnt) return a._data.selector_cnt > b._data.selector_cnt ? 1 : -1;
if (a._data.main_cnt != b._data.main_cnt) return a._data.main_cnt < b._data.main_cnt ? 1 : -1;
if (a._data.depth != b._data.depth) return a._data.depth < b._data.depth ? 1 : -1;
if (a._data.offset_top != b._data.offset_top) return a._data.offset_top < b._data.offset_top ? 1 : -1;
return 0;
});
if (big_imgs.length == 0) {
return ;
}
big_imgs = big_imgs.slice(0, 3);
_.each(big_imgs, function(img) {
_.remote_log('big img: '+img._data.selector, img);
});
_.each(event_nodes, function(node) {
var distance = 0, img = null;
for (var _node = node; _node; _node = _node.parentNode) {
var imgs = _node.querySelectorAll('img');
for (var i=0, iLen=imgs.length; i<iLen; i++) {
if (big_imgs.indexOf(imgs[i]) != -1) {
img = imgs[i];
break;
}
}
if (img) break;
distance ++;
}
if (!img) return;
node._data.nearest_img_distance = distance;
node._data.nearest_img = img;
});
var iCnt = 0, saved_tree = [];
function do_record(do_func) {
var dom_change = _.record_dom_change();
dom_change.addListener(_.debounce(function(ev) {
if (dom_change.stoped) return;
dom_change.stop();
var tree = _.dump_tree(this.changed_elements);
var ok = false;
for (var i=0, iLen=big_imgs.length; i<iLen; i++) {
if (tree.querySelector(big_imgs[i]._data.parent_selector)) {
ok = true;
break;
}
}
if (!ok) {
actions.shift();
try_next(actions);
return;
}
var dom_string = _.toString(tree);
if (dom_string === "") {
actions.shift();
try_next(actions);
return;
}
if (saved_tree.indexOf(dom_string) != -1)
return;
saved_tree.push(dom_string);
_.save(''+(iCnt++)+'_dom', dom_string);
_.remote_log('dom_saved!');
actions = []; //we got it empty actions!
if (iCnt<100)
do_record(do_func);
}, 1000));
do_func();
//var timer = setInterval(function() {
//if (dom_change.stoped || dom_change.changed) clearInterval(timer);
//else do_func();
//}, 500);
return dom_change;
}
var actions = [];
actions.push(function() {
// keydown 39
_.remote_log('key39 press');
_.keydown(39);
});
event_nodes = event_nodes.sort(function(a, b) {
var _a = a, _b = b;
a = a._data; b = b._data;
if (a.is_next != b.is_next) return b.is_next ? 1 : -1;
if (a.nearest_img._data.selector_cnt != b.nearest_img._data.selector_cnt) return a.nearest_img._data.selector_cnt > b.nearest_img._data.selector_cnt ? 1 : -1;
if (a.nearest_img_distance != b.nearest_img_distance) return a.nearest_img_distance > b.nearest_img_distance ? 1 : -1;
if (a.main_cnt != b.main_cnt) return a.main_cnt < b.main_cnt ? 1 : -1;
if (a.nearest_img._data.main_cnt != b.nearest_img._data.main_cnt) return a.nearest_img._data.main_cnt < b.nearest_img._data.main_cnt ? 1 : -1;
if (_a.offsetLeft != _b.offsetLeft) return _a.offsetLeft < _b.offsetLeft ? 1 : -1;
});
event_nodes = event_nodes.slice(0, 5);
for (var i=0, iLen=event_nodes.length; i<iLen; i++) {
_.remote_log('click_item: '+_.get_selector(event_nodes[i]), event_nodes[i]);
actions.push((function(elem) {
return function() {
_.remote_log('click '+_.get_selector(elem));
_.click(elem);
};
})(event_nodes[i]));
}
function try_next(actions) {
if (actions.length === 0) return;
if (!actions[0]) {
actions.shift();
try_next(actions);
}
var dom_change = do_record(actions[0]);
setTimeout(function() {
_.remote_log('timeout arrived!');
if (!dom_change.stoped && !dom_change.changed) {
_.remote_log('dom_change not changed!');
dom_change.stop();
actions.shift();
try_next(actions);
}
}, 500);
}
// remove changed blocks without actions
var blocked_elements = [];
var dom_change = _.record_dom_change();
setTimeout(function() {
dom_change.stop();
_.each(dom_change.changed_elements, function(elem) {
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
});
blocked_elements = dom_change.changed_elements;
try_next(actions);
}, 1000);
//_.sunflower_stop();
});
_.save('type', 'taotu');
_.remote_log('href '+location.href);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment