// ==UserScript==
// @name dev_note_search2
// @namespace dev_note_search2
// @description searching notes!
// @match http://*.deviantart.com/notifications/notes/*
// @match https://*.deviantart.com/notifications/notes/*
// @version 1.1.18
// @author http://dediggefedde.deviantart.com
// @grant none
// ==/UserScript==
function injected(){
var mapfolder=[];
var mapwords=[];
//speed up indexing notes!
//Amount of notes requested on each index-cycle.
//But: progressbar can only update once a cycle!
//numbers for a 380 Notes Scan:
//370: 4884 ms needed - 77,8 Notes/s
//100: 6487 ms needed - 58,6 Notes/s <-standard
//50: 7950 ms needed - 47,8 Notes/s
//10: 17714 ms needed - 21,5 Notes/s
//if you've got around 10.000 Notes (default: 2.8 min) you can reduce the time by settings this number higher!
//Any Value above 100 will increase the update-speed and decrease how often the Progressbar is updated.
//Any Value above your total amount of Notes won't make a difference.
var note_index_steps=100;
if (typeof uneval === "undefined") {
uneval = function(a){
return (JSON.stringify(a))||'';
};
}
//remove the /* and */ and reload to remove all stored data!
//Put them back to use the script afterwards!
/*
var keys = GM_listValues();
for (var i=0, key=null; key=keys[i]; i++) {
GM_deleteValue(key);
}
*/
// var $=unsafeWindow.jQuery,holder,query,offset,fPage,pPage,lPage;
// var DiFi=unsafeWindow.DiFi;
var noteauthor=[]; //list of authors
var notetitle=[]; //list of titles
var notetext=[]; //list of word -> list of index for other lists
var notedata=[]; //note-id, folder, note-date
var noteamount=[]; //count , updatedate
var safheader=""; //old note-menu stored to be restored when leaving search
var lastactfolder=""; //last active folder for continue indexing
var aktfolder=""; //current selected folder (per dropdown)
var aktindexfirstnoteid=""; //last note scanned in indexing -> used in updating index.
var totalamm; //total amount of notes in current folder
var newaddedli; // added notes used by checknewnotes
var toindexnoteoffsets=[]; //note's offset that still needs to be scanned
var resarr=[]; //array of note-indices that matches the current search
var aktsort=4; // sorting of search results: up&down: 01 name|23 author|45 date
var GM_setValue; //indexedDB: replace GM_functions!
var transaction; //indexedDB
var objectStore; //indexedDB
//style
var sty=document.createElement("style");
sty.innerHTML="h2.dev_note_search2_search input[type='text']{"+
"background-color: #BBCCBA;"+
"border: 1px inset #5E7264;"+
"border-radius: 7px;"+
"color: #3C4441;"+
"display: inline-block;"+
"margin-left: 10px;"+
"padding: 2px;"+
"padding-left:4px;"+
"width:70%;"+
"vertical-align: middle;}"+
"div.dev_note_header{"+
"background: linear-gradient(0deg, rgba(0,0,0,0.2) 0%, rgba(255,255, 255, 0.5) 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);"+
"padding: 0 0 0 6px!important;height:20px;}"+
"div.dev_note_header>div{"+
"height:20px;cursor:pointer;}"+
"li.dev_noteentry>span, div.dev_note_header>div{"+
"display:inline-block;"+
"width:33.33%;"+
"}"+
"#dev_note_search2_search_info{"+
"font-size:8pt;width:30%;margin:0;}"+
"li.dev_noteentry{"+
"min-height: 5px !important;"+
"cursor:pointer;"+
"padding:6px 0 6px 6px!important;"+
"}"+
"h2.dev_note_search2_search span{"+
"margin-left: 10px;"+
"width: 80px;"+
"display: inline-block;"+
"vertical-align: middle;"+
"font-size:10pt;}"+
"#dev_note_search2_search_index, #dev_note_search2_removeall_index{"+
"position:absolute;right:0;height:18px;font-size:8pt;padding:0;"+
"}"+
"#dev_note_search2_removeall_index{right:70px;}"+
"h2.dev_note_search2_search span.dev_note_search2_search_header{"+
"font-size:14pt;height:30px;display:inline-block;}"+
".dev_aktsort_down{"+
// "background: linear-gradient(0deg, #afdbae 0%, #E4F4E3 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);}"+
"background: linear-gradient(0deg, rgba(175,155,40,0.2) 0%, rgba(72, 194, 27, 0.5) 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);}"+
".dev_aktsort_up{"+
"background: linear-gradient(180deg, rgba(175,155,40,0.2) 0%, rgba(72, 194, 27, 0.5) 100%) repeat scroll 0 0 rgba(0, 0, 0, 0);}"+
"h2.dev_note_search2_search input[type='submit'],h2.dev_note_search2_search select{"+
"border-radius: 7px;"+
"background: linear-gradient(0deg, #E2E9E3, #D3DFD5) repeat scroll 0 0 transparent;"+
"border: 1px solid #93A98F;"+
"padding: 3px;"+
"margin: 6px;"+
"float: left;"+
"cursor:pointer;"+
"color: #2C3635;}"+
"h2.dev_note_search2_search input[type='submit']:active{"+
"border:1px inset #93A98F;"+
"background: linear-gradient(180deg, #E2E9E3, #B5C9B8) repeat scroll 0 0 transparent;}";
document.body.appendChild(sty);
//removes all elements of array subtrahend from array minuend with creating a new one.
function arrsubstract(minuend, subtrahend){
var ruckarr=[];
for(var i=0;i<minuend.length;i++)
if(subtrahend.indexOf(minuend[i])==-1)ruckarr.push(minuend[i]);
return ruckarr;
}
//merges two array unique into a 3rd one.
function arrmerge(arr1, arr2){
var ruckarr=getUnique(arr1);
if(arr2==null)return arr1;
if(arr1==null)return arr2;
for(var i=0;i<arr2.length;i++)
if(ruckarr.indexOf(arr2[i])==-1)ruckarr.push(arr2[i]);
return ruckarr;
}
//makes an array unique
function getUnique(arr){
var u = {}, a = [];
if(arr==null)return arr;
for(var i = 0, l = arr.length; i < l; ++i){
if(u.hasOwnProperty(arr[i])) {
continue;
}
a.push(arr[i]);
u[arr[i]] = 1;
}
return a;
}
//returns an array with all elements from two array that are in both.
function getintersection(arr1,arr2){
var resarr=new Array();
if(arr1==null)return arr2;
if(arr2==null)return arr1;
for (var i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) != -1) {
resarr.push(arr1[i]);
}
}
return resarr;
}
//remove slashes from string
function stripslashes(str) {
str=str.replace(/\\'/g,'\'');
str=str.replace(/\\"/g,'"');
str=str.replace(/\\0/g,'\0');
str=str.replace(/\\\\/g,'\\');
return str;
}
//takes a quary-string and returns a list of matched note-indices (regarding the script-lists)
//"" and * are handled here, + and - on the click-event.
function search(query,mode){ //mode: 0:author, 1: title, 2:text
try{
var returnarr=[];
if(query==""||query=="*")return null; //empty searches
query=query.toLowerCase(); //case insensitive
var inquote=false; //this block replaces all spaces with $ within quotes.
for(var i=0;i<query.length;i++){
if(inquote){
if(query[i]==" ")query=query.substr(0,i)+"$"+query.substr(i+1);
if(query[i]=="\""||query[i]=="'")inquote=false;
}else{
if(query[i]=="\""||query[i]=="'")inquote=true;
}
}
query=query.replace(/["']/g,""); //remove quotes. protected spaces are now $
switch(mode){
case 0: //author search
var searchwords=query.split(" ");
for(var j=0;j<searchwords.length;j++){ //any of those words
for(var i=0;i<noteauthor[aktfolder].length;i++){ //all found note-indices
if(noteauthor[aktfolder][i].toLowerCase().indexOf(searchwords[j].replace(/\$/g," "))!=-1)returnarr.push(i); //add found note-index to return-array if not already part of
}
}
break;
case 1: //title search: like author
var searchwords=query.split(" ");
for(var j=0;j<searchwords.length;j++){
for(var i=0;i<notetitle[aktfolder].length;i++){
if(notetitle[aktfolder][i].toLowerCase().indexOf(searchwords[j].replace("$"," "))!=-1)returnarr.push(i);
}
}
break;
case 2: //text search:
var searchwords=query.split(" ");
for(var i=0;i<searchwords.length;i++){
if(searchwords[i].split("$").length==1){ //no protected spaces/quotes:
if(searchwords[i][searchwords[i].length-1]=="*" && searchwords[i][0]=="*"){ //*-cases: *word*
searchwords[i]=searchwords[i].substr(1,searchwords[i].length-2); //make *word* to word
var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
// for(var w in notetext[aktfolder]){ //go through all stored keywords
for(var w =0;w<mapwords[indexF].length;++w){// in notetext[indexF]){ //go through all stored keywords
if(mapwords[indexF][w].indexOf(searchwords[i])!=-1){ //a keyword contains "word"
// for(var j=0;j<notetext[aktfolder][w].length;j++) //add all note-indices of this word to the returnlist (if not already there)
for(var j=0;j<notetext[indexF][w].length;j++) //add all note-indices of this word to the returnlist (if not already there)
// returnarr.push(parseInt(notetext[aktfolder][w][j]));
returnarr.push(parseInt(notetext[indexF][w][j]));
}
}
}else if(searchwords[i][searchwords[i].length-1]=="*"){ //*-cases: word*
searchwords[i]=searchwords[i].substr(0,searchwords[i].length-1); //word* -> word
var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
for(var w =0;w<mapwords[indexF].length;++w){// in notetext[indexF]){
if(mapwords[indexF][w].indexOf(searchwords[i])==0){ //keyword beginns with "word"
for(var j=0;j<notetext[indexF][w].length;j++)
returnarr.push(parseInt(notetext[indexF][w][j]));
}
}
}else if(searchwords[i][0]=="*"){ //*-cases: *word
searchwords[i]=searchwords[i].substr(1); //*word -> word
var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
for(var w =0;w<mapwords[indexF].length;++w){// in notetext[indexF]){
if(mapwords[indexF][w].indexOf(searchwords[i])==mapwords[indexF][w].length-searchwords[i].length){ //keyword ends with "word"
for(var j=0;j<notetext[indexF][w].length;j++)
returnarr.push(parseInt(notetext[indexF][w][j]));
}
}
}else{ //no * case
var indexF=mapfolder.indexOf(aktfolder);if(indexF<0)indexF=0;
var indexW=mapwords[indexF].indexOf(searchwords[i]);
// console.log(indexW,notetext[indexF].length,typeof notetext[indexF][indexW],indexW >-1 , notetext[indexF].length<indexW , typeof notetext[indexF][indexW]!= "undefined");
if(indexW >-1 && notetext[indexF].length>indexW && typeof notetext[indexF][indexW]!= "undefined"){
for(var j=0;j<notetext[indexF][indexW].length;j++){//add all note-indices of this word to the returnlist (if not already there)
indexW=mapwords[indexF].indexOf(searchwords[i]);
returnarr.push(parseInt(notetext[indexF][indexW][j]));
}
}
// console.log(returnarr);
}
}else{ //protected spaces/quotes -> $
returnarr=returnarr.concat(search(searchwords[i].replace(/\$/g," ").trim(),mode));
//make a normal search like there were no "
var leerwords=searchwords[i].split("$"); //words within quotes
var aktretarr=returnarr;
//now make a difi-request: get the full text of the notes that matches the normal search and check if the originally search matches their text.
//if yes, the note with the data-noteid-property will get removed.
for(var j=0;j<aktretarr.length;j++){
DiFi.pushPost('Notes', 'display_note', [aktfolder,notedata[aktfolder][aktretarr[j]][0]],function(success,data){
var tnotetext=$(data.response.content.body).find("textarea.mcb-body").html();
var swords=/[^ \$]*\$([^ \$]*\$?)*/g
var row="";
while(row=swords.exec(query)){
var spacedwords=row[0].replace("$"," ");
if((tnotetext.indexOf(spacedwords)==-1&&tnotetext.indexOf("*")==-1)||
(spacedwords.indexOf("*")!=-1)&&tnotetext.match(new RegExp(spacedwords.replace(/\*/g,"[^ ]*?"),"i"))==null){
$("li.note[data-noteid="+data.response.content.noteid+"]").remove();
}
}
// tnotetext
});
}
// DiFi.timer(2000); //just for record: this will do send() after 2s.
DiFi.send(); //bunch the pushpost before sending makes it into one request which is faster.
}
}
break;
}
}catch(ex){
console.log("Search error",ex);
return [];
}
return returnarr;
}
//load the data from indexedDB for this folder
//will be called the number of folders times.
function loaddata(folder){
transaction = db.transaction(["devnotesearch2"], "readwrite"); //new transaction for getting data
var objectStore = transaction.objectStore("devnotesearch2");
transaction.onerror = function(event) { //in case of an error, something went wrong...
console.log(event)
};
//mozilla's homepage: defining onsuccess after calling get would be fine...
//if not found, get will also succeed, but with event.target.result=undefined.
objectStore.get("noteauthor_"+folder).onsuccess=function(event){ //load authorlist
if(typeof event.target.result!="undefined")noteauthor[folder]=eval(event.target.result.value);
};
objectStore.get("notetitle_"+folder).onsuccess=function(event){//load titlelist
if(typeof event.target.result!="undefined")notetitle[folder]=eval(event.target.result.value);
};
objectStore.get("notedata_"+folder).onsuccess=function(event){ //load data-list (see header-variables)
if(typeof event.target.result!="undefined")notedata[folder]=eval(event.target.result.value);
};
objectStore.get("noteamount_"+folder).onsuccess=function(event){ //load stored amount and last update
if(typeof event.target.result!="undefined")noteamount[folder]=eval(event.target.result.value);
};
objectStore.get("toindexnoteoffsets").onsuccess=function(event){ //load last indexed note.
if(typeof event.target.result!="undefined")toindexnoteoffsets=eval(event.target.result.value);
};
objectStore.get("lastindexfolder").onsuccess=function(event){ //load last indexed folder
if(typeof event.target.result!="undefined")lastindexfolder=event.target.result.value;
};
objectStore.get("notetext_"+folder).onsuccess=function(event){ //load all the content-data (word-lists)
if(typeof event.target.result=="undefined")return;
//word(18)noteid(19)wordpos(18)noteid(19)wordpos(17)word(18)noteid(19)wordpos
var rawdata=event.target.result.value.split(String.fromCharCode(17));
var zrawdata1="", zrawdata2="";
var indexW,indexF;
if(mapfolder.indexOf(folder)==-1){
mapfolder.push(folder);
indexF=mapfolder.indexOf(folder);
mapwords[indexF]=[];
}else
indexF=mapfolder.indexOf(folder);
notetext[indexF]=new Array();
// console.log(rawdata);
for(var i=0;i<rawdata.length;i++){
zrawdata1=rawdata[i].split(String.fromCharCode(18)); //noteid(19)wordpos
zrawdata2=zrawdata1.shift(); //word
if(mapwords[indexF].indexOf(zrawdata2)==-1)
mapwords[indexF].push(zrawdata2);
indexW=mapwords[indexF].indexOf(zrawdata2);
// notetext[folder][zrawdata2]=zrawdata1;
notetext[indexF][indexW]=zrawdata1;
}
// console.log(mapwords,mapfolder);
//display the info-text
$("#dev_note_search2_search_folders").change();
};
}
//convert the note's message into word-list entries
function adddata(message, noteid, folder){
try{
if(message==null||message=="")return;
var elements=message.replace(/[\W\s]/g," ").replace(/ {2,}/," ").split(" "); //only \w-character words are liked. numbers are part of \w
for(var i =0;i<elements.length;i++){ //all new words
if(typeof elements[i]=="undefined"||elements[i]==""||elements[i][0]==" ")continue; //empty words and strange accidents don't count.
elements[i]=elements[i].toLowerCase(); //case insensitive
var indexF=mapfolder.indexOf(folder);
if(mapwords.length<=indexF||indexF<0||notetext.length<=indexF)continue;
var indexW=mapwords[indexF].indexOf(elements[i]);
if(typeof notetext[indexF]=="undefined"){ //word not yet listed
notetext.push([[noteid]]);
} else { //word already part of list
if(indexW<0){
mapwords[indexF].push(elements[i]);
notetext[indexF].push([]);
}
indexW=mapwords[indexF].indexOf(elements[i]);
if(indexW<0||indexW>=notetext[indexF].length||typeof notetext[indexF][indexW]=="undefined")continue;
if(
$.inArray(noteid, notetext[indexF][indexW])==-1
//this note is not already added (e.g. 2 times word in a note)
&¬etext[indexF][indexW].push) //and the array is legit
notetext[indexF][indexW].push(noteid); //then add this note's index (pointing to other lists)
}
}
}catch(ex){
console.log("MSG-convert error: ",ex);
return;
}
}
//this goes from newest to oldest note until it finds a note with the last indexed note id, stored in noteamount[folder][2]
//this is actually how getnotes() also looked like before made pausable and turning the pushposts into bunches.
function checknewnotes(folder,offset){
if(offset==40)return;
//in case there is no last indexed id as there was no index, make a full index
var indexF=mapfolder.indexOf(folder);
// var indexW=mapwords[indexF].indexOf(elements[i]);
// if(typeof notetext[folder]=="undefined"&&totalamm!=-1){getnotes(folder,Math.floor(totalamm/10)*10,true);return;}
if((indexF<0 || typeof notetext[indexF]=="undefined")&&totalamm!=-1){getnotes(folder,Math.floor(totalamm/10)*10,true);return;}
if(totalamm==-1){ //folder unknown full
noteauthor[folder]=[]; //everywhere 0!
notetitle[folder]=[];
notetext[indexF]=[];
notedata[folder]=[];
// mapfolder=[];
// mapwords=[];
noteamount[folder]=[0,(new Date).toLocaleString(),""];
lastindexfolder=folder;
aktindexfirstnoteid="";
var intex="";
saveindexnotes(folder, intex); //save 0...
$("#dev_note_search2_search_folders").change(); //display 0 Notes indexed
}
DiFi.pushPost('Notes', 'display_folder', [folder,offset,false],function(success,data){
var aktsite=$(data.response.content.body); //parse note-page (<10 notes)
aktsite.find("li.note").each(function(){ //break when the last indexed note was found. All notes before that (newer) will be in newaddedli.
if($(this).attr("data-noteid")!=noteamount[folder][2]){
newaddedli=newaddedli.add($(this));
}else
return false; //false will break the each-loop
});
if(newaddedli.length==0)return; //no new notes
if(aktsite.find("li.note[data-noteid='"+noteamount[folder][2]+"']").length==0&&aktsite.find("li.note").length>0){ //the last indexed note is not on this site
checknewnotes(folder,offset+10); //recursive call to scan the next page.
}else{
//reverse order of found new notes (convert to oldes->newest)
$(newaddedli.get().reverse()).each(function(){
if(NoteAlreadyScanned($(this).attr("data-noteid"),folder))return;
//username is a must have.
if($(this).find("span.sender a.username,span.sender span.username").html()==null){
return;
}
if(typeof $(this).find("div.note-preview").html()=="undefined"){
noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
notetitle[folder].push($(this).find("span.subject a").html());
var dstime=Date.parse($(this).find("span.ts").attr("title"));
if(isNaN(dstime))dstime=Date.parse($(this).find("span.ts").html());
aktindexfirstnoteid=$(this).attr("data-noteid");
notedata[folder].push(new Array($(this).attr("data-noteid"),
$(this).find("span.subject a").attr("data-folderid"),
dstime));
return;
}
noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
//otherwise noteauthor has a problem
notetitle[folder].push($(this).find("span.subject a").html());
//title just assumes, there is a note title
//no convert and add the text into word-list.
//note-preview contains the whole text, but without linebreaks(spaces inserted) and without html
//notedata[folder].length is the new index after this entry is pushed into notedata!
adddata($(this).find("div.note-preview").html(),notedata[folder].length,folder);
//parse the time when the note was sent/recieved.
var dtime=Date.parse($(this).find("span.ts").attr("title"));
if(isNaN(dtime))dtime=Date.parse($(this).find("span.ts").html());
//the display switches: one says the date, one xx minutes ago.
aktindexfirstnoteid=$(this).attr("data-noteid"); //last indexed note will be overwritten untill the newset index.
//add note-id, folderid and recieved date to notedata.
notedata[folder].push(new Array($(this).attr("data-noteid"),
$(this).find("span.subject a").attr("data-folderid"),
(new Date(dtime)).toLocaleString()));
});
var intex="";
saveindexnotes(folder,intex);
//progressbar and title
$("#dev_note_search2_search_index").css("background-image","").attr("title","100%: "+noteauthor[folder].length+"/"+totalamm+", "+Math.round(100*(intex.length+uneval(noteauthor[folder]).length+uneval(notetitle[folder]).length+uneval(notedata[folder]).length)/1024/1024)/100+"MB storage used");
}
// }
});
DiFi.send();
}
// var aktstartdat; //time measurement.
//saves the values to indexedDB!
function saveindexnotes(folder, intex){
try{
if(typeof intex=="undefined"||intex==null)intex="";
var indexF=mapfolder.indexOf(folder);
// var indexW=mapwords[indexF].indexOf(elements[i]);
// for(var el in notetext[folder]){//convert word-list into a string. saves some bytes in contrast to uneval().
// intex+=String.fromCharCode(17)+el+String.fromCharCode(18)+notetext[folder][el].join(String.fromCharCode(18));
// }
for(var el =0;el<mapwords[indexF].length;++el){//in notetext[indexF]){//convert word-list into a string. saves some bytes in contrast to uneval().
intex+=String.fromCharCode(17)+mapwords[indexF][el]+String.fromCharCode(18)+notetext[indexF][el].join(String.fromCharCode(18));
}
//noteamount, updatedate and last indexed note to be changed
noteamount[folder]=[noteauthor[folder].length,(new Date).toLocaleString(),aktindexfirstnoteid];
//elements in folder...
//this updates info-text during scan
if(typeof noteamount[aktfolder]!="undefined"&¬eamount[aktfolder].length>1)
$("#dev_note_search2_search_info").html(noteamount[aktfolder][0]+" Notes fetched<br/> Updated on"+noteamount[aktfolder][1]);
// setTimeout(function(){ //neded for the original GM_setValue. Now IndexDb
GM_setValue("notetext_"+folder,intex.substr(1));
GM_setValue("noteauthor_"+folder,uneval(noteauthor[folder]));
GM_setValue("notetitle_"+folder,uneval(notetitle[folder]));
GM_setValue("noteamount_"+folder,uneval(noteamount[folder]));
GM_setValue("notedata_"+folder,uneval(notedata[folder]));
GM_setValue("toindexnoteoffsets",uneval(toindexnoteoffsets));
GM_setValue("lastindexfolder",uneval(lastindexfolder));
// },0);
}catch(ex){
console.log("indexDB-storage error: ",ex);
return;
}
}
function NoteAlreadyScanned(id,folder){
try{
for(var i=0;i<notedata[folder].length;i++)
if(notedata[folder][i][0]==id)return true;
return false;
}catch(ex){
console.log("Note-Check error: ",ex);
return;
}
}
//index your notes anew or continue after break.
function getnotes(folder,offset,neu){
try{
if(typeof folder=="undefined"||folder<0)return;
if(totalamm==0){ //folder empty
noteauthor[folder]=new Array(); //everywhere 0!
notetitle[folder]=new Array();
notetext[folder]=[];
if(mapfolder.indexOf(folder)<0){
mapfolder.push(folder);
mapwords.push([]);
}
notedata[folder]=new Array();
noteamount[folder]=[0,(new Date).toLocaleString(),""];
lastindexfolder=folder;
aktindexfirstnoteid="";
var intex="";
saveindexnotes(folder, intex); //save 0...
$("#dev_note_search2_search_folders").change(); //display 0 Notes indexed
return;
}
if(neu){ //indexing started
if(toindexnoteoffsets.length>0){return;} //already running!
noteauthor[folder]=[];
notetitle[folder]=[];
if(mapfolder.indexOf(folder)<0){
mapfolder.push(folder);
mapwords.push([]);
}
notedata[folder]=[];
noteamount[folder]=[];
lastindexfolder=folder;
aktindexfirstnoteid="";
for(var i=offset;i>=0;i-=10) //create all note-offset I want to scan! offset=(page-1)*10.
toindexnoteoffsets.push(i); //go from high to 0: old notes first!
}
if(offset==-10){ //finished: all notes scanned, toindexnoteoffsets empty.
var intex="";
saveindexnotes(folder, intex); //save all data.
//update progressbar
if(typeof noteauthor[folder]=="undefined"||noteauthor[folder]==null)return;
$("#dev_note_search2_search_index").css("background-image","").attr("title","100%: "+noteauthor[folder].length+"/"+totalamm+", "+Math.round(100*(intex.length+uneval(noteauthor[folder]).length+uneval(notetitle[folder]).length+uneval(notedata[folder]).length)/1024/1024)/100+"MB storage used");
//update info-text
$("#dev_note_search2_search_folders").change();
}else{
var runter=note_index_steps; //number of offsets within a request. Is set at top. default 100
if(offset%note_index_steps!=0)runter=offset%note_index_steps; //360: first 6*10, then only 10*10.
for(var i=0;i<toindexnoteoffsets.length&&i<runter/10;i++){ //bunch of difi-posts.
DiFi.pushPost('Notes', 'display_folder', [folder,toindexnoteoffsets[i],false],function(success,data){
//remove offset from list
toindexnoteoffsets.splice(toindexnoteoffsets.indexOf(parseInt(data.response.content.offset)),1);
//update progressbar
if(totalamm==0)totalamm=1;
$("#dev_note_search2_search_index").css("background-image","linear-gradient(90deg, #9AD15F "+(Math.round((totalamm-toindexnoteoffsets.length*10)/totalamm*100))+"%, #D3DFD5 "+(Math.round((totalamm-toindexnoteoffsets.length*10)/totalamm*100)+10)+"%)").attr("title",Math.round((totalamm-toindexnoteoffsets.length*10)/totalamm*100)+"%: "+(totalamm-toindexnoteoffsets.length*10)+"/"+totalamm);
//get jquery-object for notes page
var aktsite=$(data.response.content.body);
if(aktsite.find("li.note").length!=0){ //no empty pages
//reverse order for oldes to newest notes!
$(aktsite.find("li.note").get().reverse()).each(function(){
// see checknewnotes for this
try{
if(NoteAlreadyScanned($(this).attr("data-noteid"),folder))return false; //true: next item
if($(this).find("span.sender a.username,span.sender span.username").html()==null){ //no sender recognized
return true; //true: next item;
}
if(typeof $(this).find("div.note-preview").html()=="undefined"){
noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
notetitle[folder].push($(this).find("span.subject a").html());
var dstime=Date.parse($(this).find("span.ts").attr("title"));
if(isNaN(dstime))dstime=Date.parse($(this).find("span.ts").html());
if(isNaN(dstime))dstime=0;
aktindexfirstnoteid=$(this).attr("data-noteid");
notedata[folder].push(new Array($(this).attr("data-noteid"),
$(this).find("span.subject a").attr("data-folderid"),
dstime));
return true; //no preview: next item
}
noteauthor[folder].push($(this).find("span.sender a.username,span.sender span.username").html());
notetitle[folder].push($(this).find("span.subject a").html());
adddata($(this).find("div.note-preview").html(),notedata[folder].length,folder);
var dtime=Date.parse($(this).find("span.ts").attr("title"));
if(isNaN(dtime))dtime=Date.parse($(this).find("span.ts").html());
aktindexfirstnoteid=$(this).attr("data-noteid");
notedata[folder].push(new Array($(this).attr("data-noteid"),
$(this).find("span.subject a").attr("data-folderid"),
dtime));
}catch(ex2){
console.log("Error checking Offset "+offset+":",ex2);
return true; //error: next item;
}
});
saveindexnotes(folder);
//all note's scanned: call the finish-feature of this functio
//are note_index_steps note scanned at once, you can scan the next note_index_steps Notes!
if(toindexnoteoffsets.length==0)getnotes(folder,-10,false); else
if((toindexnoteoffsets.length*10-10)%note_index_steps==0)getnotes(folder,(toindexnoteoffsets.length*10-10),false);
}
});
}
DiFi.send();
}
}catch(ex){
console.log("Error in fetching notes: ",ex);
return;
}
}
function addlayout(){
if($("dev_note_search2_tab").length>0)return;
aktfolder="1"; //standard is inbox.
aktsort=4; //standard is sorting results with date
resarr=[]; //show no notes at the beginning (index of notes to show)
//search-entry on the left
var tab=$('<a class="f folder-link dev_search_tab" title="Search" href="#" onclick="return false;" id="dev_note_search2_tab"><i class="icon i1"></i><span class="ttext">Search</span></a>');
//make the search-form undo-able
$("div.messages-menu div.pager-holder div.pager2 div.page2").children().click(function(){
if(safheader!=""){
$("h2.mczone-title").empty();
$("h2.mczone-title").css("height","");
$("h2.mczone-title").first().append(safheader);
}
if(lastactfolder!=""){ //switch to last selected folder!
lastactfolder.addClass("selected");
$("#dev_note_search2_tab").removeClass("selected");
}
});
$("#notes a.folder-link").first().before(tab); //insert "search"
// $("div.messages-menu div.pager-holder div.pager2 div.page2 div.header").first().after(tab); //insert "search"
tab.click(function(event){//and click event
event.preventDefault();
event.stopPropagation(); //no parent-clicks needed!
$(".dev_note_header").remove(); //no double search forms!
//folder where you came from
lastactfolder=$("div.messages-menu div.pager-holder div.pager2 div.page2 a.selected").removeClass("selected").first();
$("#dev_note_search2_tab").addClass("selected"); //search is now selected
if($("#dev_note_search2_search_title").length==0)safheader=$("h2.mczone-title").first().children();
var header1=$("td.notes-left h2.mczone-title").first().empty();
var header2=$("td.notes-right h2.mczone-title").first().empty(); //no double search forms!
header1.addClass("dev_note_search2_search");
header2.addClass("dev_note_search2_search");
$( window ).resize(function(){ //adapt search form to window's site
$("#dev_note_search2_search_info").width($("h2.dev_note_search2_search").eq(1).width()-320);
$("h2.dev_note_search2_search input[type='text']").width($("h2.dev_note_search2_search").first().width()-130);
});
//inset search form
header1.append($("<span class='dev_note_search2_search_header'>Search:</span><div class='dev_search_formfield'><span>Username:</span><input id='dev_note_search2_search_name' type='text'/></div>"+
"<div class='dev_search_formfield'><span>Subject:</span><input id='dev_note_search2_search_title' type='text'/></div><div class='dev_search_formfield'><span>Text:</span><input id='dev_note_search2_search_text' type='text'/></div>")).css({"height":"110px","background-size":"contain","padding":"10px 0px"});
header1.find("input[type='text']").keydown(function(event){ //enter means search!
if(event.which==13)$("#dev_note_search2_search_submit").click();
});
header2.append("<input type='submit' onclick='return false;' id='dev_note_search2_search_submit' value='Search'/>"+
"<input type='submit' onclick='return false;' id='dev_note_search2_search_addindex' value='Refresh'/>"+
"<select id='dev_note_search2_search_folders'></select><span id='dev_note_search2_search_info'></span>");
header1.prepend("<input type='submit' onclick='return false;' id='dev_note_search2_search_index' value='Index Notes'/>");
header1.prepend("<input type='submit' onclick='return false;' id='dev_note_search2_removeall_index' value='Reset to Default'/>");
$("#dev_note_search2_search_addindex").first().click(function(){ //refresh-button to update index
//total amount of notes is displayed at each note-folder's rel-attribute
totalamm=parseInt($("a.folder-link[data-folderid="+aktfolder+"]").attr("rel").replace(/,/g,""));
newaddedli=$([]);
checknewnotes(aktfolder,0);
});
//load data for each folder and generate the dropdown!
$("div.messages-menu div.pager-holder div.pager2 div.page2 a.folder-link").not(".dev_search_tab").each(function(){
if($(this).html()=="Search")return;
var wert=$(this).attr("data-folderid");
if(typeof(noteamount[wert])=="undefined"){ //only load first
// setTimeout(function(){
loaddata(wert);
// },0);
}
$("#dev_note_search2_search_folders").first().append("<option value='"+$(this).attr("data-folderid")+"'>"+$(this).attr("title")+"</option>");
});
$("#dev_note_search2_search_folders option").first().addClass("selected"); //select "inbox"
$("#dev_note_search2_search_folders").change(function(){ //change will update the info-text and chooses aktfolder
if($(this).prop("selectedIndex")==-1)$(this).prop("selectedIndex",0); //stange=first
aktfolder=$(this).val();
if(toindexnoteoffsets.length>0){ //continue scan?
if(confirm("You interrupted the last scan of your folder '"+lastindexfolder+"'.\n Do you want to continue indexing it?")){
totalamm=parseInt($("a.folder-link[data-folderid="+aktfolder+"]").attr("rel").replace(/,/g,""));
getnotes(aktfolder,0,false);
}else{ //no...
toindexnoteoffsets=[];
// GM_setValue("toindexnoteoffsets",uneval(toindexnoteoffsets));
}
}
if(typeof(noteamount[aktfolder])=="undefined") //no indexed notes!
$("#dev_note_search2_search_info").html("No notes fetched so far!<br/>Press \"Index Notes\"!");
else //show the indexed note's amount and update-Date in the info-text-field!
$("#dev_note_search2_search_info").html(noteamount[aktfolder][0]+" Notes fetched<br/> Updated on "+noteamount[aktfolder][1]);
}).keyup(function() { //using dropdown with keyboard
$(this).change();
}).change(); //and do it already once!
$("#dev_note_search2_removeall_index").click(function(){
location.href="http://www.deviantart.com/notifications/notes/#1_0/#killoldindex";
location.reload();
});
$("#dev_note_search2_search_index").click(function(){
//index notes!
//total amount of notes is displayed at each rel-attribute
totalamm=parseInt($("a.folder-link[data-folderid="+aktfolder+"]").attr("rel").replace(/,/g,""));
if(totalamm==-1){
newaddedli=$([]);
checknewnotes(aktfolder,0);
}else{
getnotes(aktfolder,Math.floor(totalamm/10)*10,true);
}
});
//make a search!
//here is also the actuall search and use of search() defined!
header2.find("#dev_note_search2_search_submit").click(function(){
resarr=getUnique(search($("#dev_note_search2_search_name").val(),0)); //search authors
resarr=getintersection(resarr,search($("#dev_note_search2_search_title").val(),1)); //search titles
//use intersection to have notes that match author AND title
var query=$("#dev_note_search2_search_text").val().trim(); //and now the text-search...
var queryplus=query.match(/\+("[^"]*?"|[^ "]*)/g); //all words with a + before (also +"asd dsa")
var queryminus=query.match(/-("[^"]*?"|[^ "]*)/g); //same with -
var querynotplus=query.replace(/(\+|-)("[^"]*?"|[^ "]*)/g,""); //and words with neither
if(queryplus==null) //no plus words?
resarr=getintersection(resarr,search(querynotplus,2)); //normal search
else{
for(var i=0;i<queryplus.length;i++){ //otherwise go through all + words
//and connect their searches with ANDs!
resarr=getintersection(resarr,search(queryplus[i].substr(1).trim(),2));
}
//at last merge the result with the not-plus words for an stronger OR.
resarr=arrmerge(resarr,search(querynotplus.trim(),2));
}
if(queryminus!=null){ //there were - words.
var notresarr=search(queryminus.join(" ").replace("-",""),2); //find notes with those words
resarr=arrsubstract(resarr,notresarr); //and remove them from the list!
}
resarr=getUnique(resarr); //in case something got wrong: unique id.
//WHY ARE THERE STILL DOUBLE ENTRIES?
$("div.dev_aktsort_down,div.dev_aktsort_up").click().click(); //refresh sorting!
displayresarr(); //show found notes!
});
//note-headers for sorting!
$("ul.notes").first().before($("<div class='dev_note_header'></div>").first().append($("<div class='dev_notetitle'>Subject</div>").click(function(){
$(".dev_aktsort_down").removeClass("dev_aktsort_down");
$(".dev_aktsort_up").removeClass("dev_aktsort_up");
if(resarr==null)return; //no notes to sort
if(aktsort==0){ //toggle between 0 and 1
$(this).addClass("dev_aktsort_up");
aktsort=1;
resarr=resarr.sort(function(a,b){return notetitle[aktfolder][a].toLowerCase()<=notetitle[aktfolder][b].toLowerCase();}); //sort subjects ascending
}else{
$(this).addClass("dev_aktsort_down");
aktsort=0;
resarr=resarr.sort(function(a,b){return notetitle[aktfolder][a].toLowerCase()>=notetitle[aktfolder][b].toLowerCase();}); //sort subjects descending
}
displayresarr(); //show sorted notes
})).first().append($("<div class='dev_noteauthor'>Username</div>").click(function(){
$(".dev_aktsort_down").removeClass("dev_aktsort_down");
$(".dev_aktsort_up").removeClass("dev_aktsort_up");
if(resarr==null)return;
if(aktsort==2){//toggle between 2 and 3
$(this).addClass("dev_aktsort_up");
aktsort=3;
resarr=resarr.sort(function(a,b){return noteauthor[aktfolder][a].toLowerCase()<=noteauthor[aktfolder][b].toLowerCase();}); //sort usernames ascending
}else{
$(this).addClass("dev_aktsort_down");
aktsort=2;
resarr=resarr.sort(function(a,b){return noteauthor[aktfolder][a].toLowerCase()>=noteauthor[aktfolder][b].toLowerCase();}); //sort usernames descending
}
displayresarr();
})).first().append($("<div class='dev_notedata dev_aktsort_down'>Date</div>").click(function(){
$(".dev_aktsort_up").removeClass("dev_aktsort_up");
$(".dev_aktsort_down").removeClass("dev_aktsort_down");
if(resarr==null)return;
if(aktsort==4){//toggle between 4 and 5
$(this).addClass("dev_aktsort_up");
aktsort=5;
resarr=resarr.sort(function(a,b){return notedata[aktfolder][a][2]>=notedata[aktfolder][b][2];});
//sort dates ascending
}else{
$(this).addClass("dev_aktsort_down");
aktsort=4;
resarr=resarr.sort(function(a,b){return notedata[aktfolder][a][2]<=notedata[aktfolder][b][2];});
//sort dates descending
}
displayresarr();
})));
displayresarr(); //show no notes at the beginning
});
}
function displayresarr(){ //show the notes which indices are in resarr
var body=$("ul.notes").first();
body.empty(); //empty the old displayed list
if(resarr==null)return; //new list empty?
for(var i=0;i<resarr.length;i++){
//append a new li for every note. info and style are also inserted. also note-id in ''.
body.append($("<li class='dev_noteentry "+(i%2==0?"even":"odd")+" note ui-draggable' data-noteid='"+notedata[aktfolder][resarr[i]][0]+"' data-folderid='"+notedata[aktfolder][resarr[i]][1]+"' data-cached='false'>"+
"<span class='dev_notetitle'>"+notetitle[aktfolder][resarr[i]]+"</span>"+
"<span class='dev_noteauthor'>"+noteauthor[aktfolder][resarr[i]]+"</span>"+
"<span class='dev_notedata'>"+(new Date(notedata[aktfolder][resarr[i]][2])).toLocaleString()+"</span>"+
"</li>").click(function(){ //click on the li:
$("li.current-note").removeClass("current-note");
$(this).addClass("current-note"); //note highlight
location.href=location.href.replace(/\/\d+$/,"")+"/"+$(this).attr("data-noteid"); //adapt displayed url!
DiFi.pushPost("Notes","display_note",[$(this).attr("data-folderid"),$(this).attr("data-noteid")],function(success,data){ //display the note via difi!
$("div.push").first().html("<a id=\"note-body\" class=\"anchor\"></a>"+
stripslashes(data.response.content.body)); //difi slashes lot of things...
$("div.note-controls.current-note-actions").css("display",""); //otherwise, the buttons are hidden...
});
DiFi.send();
}));
}
}
var db;
function indexedDBinit(neu){
//indexedDB:
if(location.href.substring(location.href.length-("#killoldindex").length)=="#killoldindex"){
indexedDB.deleteDatabase('devnotesearch2');
location.href="http://www.deviantart.com/notifications/notes/#1_0/";
}
var request = indexedDB.open("devnotesearch2",1);
request.onerror = function(event) {
console.log(event);
};
request.onupgradeneeded = function(event) {
if(event!=null)db = event.target.result;
var objectStore = db.createObjectStore("devnotesearch2",{keyPath:"name"});
objectStore.createIndex("name", "name", { unique: true });
}
request.onsuccess = function(event) {
db = request.result;
db.onabort = function(e) {
db.close();
db = null;
}
// db = event.target.result;
// var objectStore = db.createObjectStore("devnotesearch2",{keyPath:"name"});
// objectStore.createIndex("name", "name", { unique: true });
try{
transaction = db.transaction(["devnotesearch2"], "readwrite");
}catch(e){
request.onupgradeneeded(null);
return;
}
objectStore = transaction.objectStore("devnotesearch2");
var putter=objectStore.put({name:"test",value:"erfolgreich"});
putter.onerror=function(event){console.log("ERR:",event);};
putter.onsuccess=function(event){};
objectStore.get("test").onsuccess=function(event){ //load authorlist
if(typeof event.target.result!="undefined")console.log(event.target.result.value);
};
transaction.onerror = function(event) {
console.log(event)
};
GM_setValue=function(Gname,Gvalue){//{name:Gname,value:Gvalue}
// transaction = db.transaction(["devnotesearch2"], "readwrite");
// var objectStore = transaction.objectStore("devnotesearch2");
// transaction.onerror = function(event) {
// console.log(event)
// };
items.push({name:Gname,value:Gvalue});
if($("#overlaysavingprocess").length==0)
$("body").append($("<div style='height:20px;width:100px;position:fixed;background-color:#aaffaa;color:#008800;top:50%;left:50%;margin-top:-10px;margin-left:-50px;border:1px solid green;z-index:99;border-radius:5px;text-align:center;line-height:20px;' id='overlaysavingprocess' len=1>Saving Data...</div>"));
else
$("#overlaysavingprocess").attr("len",parseInt($("#overlaysavingprocess").attr("len"))+1);
// var putter=objectStore.put(data);//{name:Gname,value:Gvalue}
// putter.onerror=function(event){console.log("ERR:",event);};
// putter.onsuccess=function(event){
// $("#overlaysavingprocess").attr("len",parseInt($("#overlaysavingprocess").attr("len"))-1);
// if($("#overlaysavingprocess").attr("len")==0)$("#overlaysavingprocess").remove();
// };
if(!safeworking)putNext();
};
function putNext() {
if(!safeworking){
transaction = db.transaction(["devnotesearch2"], "readwrite");
objectStore = transaction.objectStore("devnotesearch2");
}
if (items.length>0){
safeworking=true;
objectStore.put(items.shift()).onsuccess = putNext;
$("#overlaysavingprocess").attr("len",parseInt($("#overlaysavingprocess").attr("len"))-1);
if($("#overlaysavingprocess").attr("len")==0)$("#overlaysavingprocess").remove();
} else { // complete
safeworking=false;
}
}
addlayout();
};
}
var items=[];
var safeworking=false;
indexedDBinit();
};
// GM_xmlhttpRequest({
// url:"http://phi.pf-control.de/jquery_min.js",
// method:"GET",
// onload: function(data){
// eval(data.responseText);
// injected();
// }
// });
var el=document.createElement("script");
el.innerHTML="("+injected.toString()+")();";
document.body.appendChild(el);