/// chrome://wikilocaledit/content/wikilocaledit.js
/// Manage main app, which is browser panel toolbarbutton
// Requires:
// * content/fileIO.js
// * content/permissions.js
// * content/prefs.js
// * locale/locale.js
// Used by windows:
// * content/wikilocaledit.xul
/// 2012-12-12 PerfektesChaos@de.wikipedia
/// Fingerprint: #0#0#
/// <nowiki>
/*jshint curly:true, eqeqeq:true, strict:true, undef:true, white:false */
/*global document, gBrowser, HTMLDocument, window */
/*jslint white: true */
/*globals gBrowser: true, HTMLDocument: true,
document: true, window: true */
( function ( w ) {
"use strict";
var EVENTS, IO, PAGES, PREFS, TOOL, WLE, First;
if ( ! w.wikiLocalEdit ) {
w.wikiLocalEdit = { };
}
WLE = w.wikiLocalEdit;
WLE.pages = { };
PAGES = WLE.pages;
PREFS = WLE.prefs;
WLE.live = PREFS.getLeading();
EVENTS = { listening: false };
IO = { search: "*.txt; *.text; *.wiki",
select: "Wikitext: *.txt, *.text, *.wiki" };
TOOL = { };
First = function () {
// Initialize package. Start event listeners.
// Uses:
// w
// TOOL.fresh()
// Remark: Used as event handler -- 'this' is not WLE
// 2012-11-30 PerfektesChaos@de.wikipedia
w.removeEventListener( "load", First, false ); // myself
TOOL.fresh( false );
}; // First()
w.addEventListener( "load", First, false ); // -> gBrowser
EVENTS.fresh = function () {
// Update listener mode
// Postcondition:
// Listeners are activated or stopped
// Uses:
// this
// > .pages.userURLstatics
// > EVENTS.connect
// > .live
// > gBrowser
// >< EVENTS.listening
// .pages.fresh()
// DOM.addEventListener()
// DOM.removeEventListener()
// (EVENTS.onPageLoad)
// (EVENTS.onButton)
// 2012-11-30 PerfektesChaos@de.wikipedia
var e,
i,
n = this.connect.length;
PAGES.fresh();
if ( WLE.live &&
! this.listening &&
PAGES.userURLstatics ) {
for ( i = 0; i < n; i++ ) {
e = this.connect[ i ];
gBrowser.addEventListener( e[ 0 ], e[ 1 ], true, true );
} // for i
this.listening = true;
} else if ( this.listening ) {
for ( i = 0; i < n; i++ ) {
e = this.connect[ i ];
gBrowser.removeEventListener( e[ 0 ], e[ 1 ], true );
} // for i
this.listening = false;
}
}; // EVENTS.fresh()
EVENTS.onPageLoad = function ( event ) {
// Any page has been loaded into user browser.
// Postcondition:
// Returns true for continued event processing
// Uses:
// .pages.isPageUser()
// .pages.fiat()
// .pages.form()
// .pages.first()
// .pages.furnish()
// Remark: Used as event handler -- 'this' is not WLE
// 2012-11-30 PerfektesChaos@de.wikipedia
var doc,
doit,
emit = event.originalTarget, // Mozilla spec
got = PAGES.isPageUser( emit ),
socket;
if ( got ) {
doc = got[ 0 ];
doit = got[ 1 ];
socket = PAGES.fiat( doc );
if ( doit ) {
PAGES.form( doc, socket );
} else {
PAGES.first( socket );
PAGES.furnish( doc );
}
}
return true;
}; // EVENTS.onPageLoad()
EVENTS.onPressButton = function ( event ) {
// Any page has been loaded into user browser.
// Postcondition:
// Returns false for captured event processing
// Uses:
// .pages.isPageUser()
// DOM.getAttribute()
// .pages.file()
// IO.find()
// .pages.flush()
// .prefs.fetchBasedir()
// .pages.setDirBase()
// IO.fetchSubdir()
// .pages.setDirSub()
// Remark: Used as event handler -- 'this' is not WLE
// 2012-12-12 PerfektesChaos@de.wikipedia
var emit = event.originalTarget, // Mozilla spec
doc = emit.ownerDocument,
call = PAGES.isPageUser( doc ),
stuff = false,
scan, serve, specific, suffix, suggest;
if ( call ) {
serve = emit.getAttribute( "action" );
specific = emit.getAttribute( "specific" );
if ( call[ 1 ] ) {
if ( serve === "OpenFile" || serve === "SaveFileAs" ) {
scan = emit.getAttribute( "scan" );
suffix = emit.getAttribute( "suffix" );
suffix = ( suffix ? suffix : false );
suffix = suffix.replace( /[^a-zA-Z0-9]/g, "" );
}
switch ( serve ) {
case "OpenFile" :
// +text/saved leer oder gleich
stuff = emit.getAttribute( "lowcode" );
PAGES.file( specific,
scan,
suffix,
call[ 0 ],
( stuff === "true" ) );
break;
case "SaveFileAs" :
suggest = emit.getAttribute( "suggest" );
stuff = IO.find( specific,
scan,
suggest,
suffix,
true );
case "SaveFile" : // fall through
IO.flush( doc, stuff );
break;
case "Abort" :
break;
} // switch serve
} else {
switch ( serve ) {
case "DirBase" :
WLE.prefs.fetchBasedir();
PAGES.setDirBase( doc );
break;
case "DirSub" :
IO.fetchSubdir( specific );
PAGES.setDirSub( doc, specific );
break;
} // switch serve
}
}
return false;
}; // EVENTS.onPressButton()
EVENTS.connect = [
[ "load", EVENTS.onPageLoad ],
[ "wikilocaleditButton", EVENTS.onPressButton ]
];
IO.fetchSubdir = function ( account ) {
// Perform local directory sub project selection and storing
// Precondition:
// account -- DBname . user name
// Uses:
// > .locale.selectDirSub
// .prefs.getDirBase()
// .prefs.getDirSub()
// .fileIO.find()
// .prefs.setDirSub()
// 2012-12-12 PerfektesChaos@de.wikipedia
var n, s,
start = WLE.prefs.getDirBase();
s = WLE.fileIO.find( start + WLE.prefs.getDirSub( account ),
false,
false,
false,
WLE.locale.selectDirSub + "\n" + account,
false );
if ( typeof s === "string" ) {
n = start.length;
if ( s.substr( 0, n ) === start ) {
s = s.substr( n );
} else {
s = "";
}
WLE.prefs.setDirSub( s, account );
}
}; // IO.fetchSubdir()
IO.file = function ( account, achieve, assign, access, ansi ) {
// Retrieve file name and content and put into textarea
// Precondition:
// account -- sub path for: DBname / user name
// achieve -- pattern string
// assign -- suffix for new file
// access -- document of user edit web page
// ansi -- input file is not utf-8
// Uses:
// IO.find()
// .fileIO.feed()
// (IO.filled)
// 2012-12-12 PerfektesChaos@de.wikipedia
var stuff = IO.find( account, achieve, false, assign, false );
if ( stuff ) {
WLE.fileIO.feed( stuff, access, this.filled, ansi );
}
}; // IO.file()
IO.filled = function ( arglist ) {
// Callback after asynchronous reading from local file
// Precondition:
// arglist -- Array, or false
// [0] path (appoint)
// [1] true: write protected
// [2] content, or false
// [3] document of user web page
// achieved -- string with file content
// Uses:
// >< .pages.windows
// .pages.fiat()
// .pages.form()
// .pages.fill()
// Remark: Used as event handler -- 'this' is not IO
// 2012-11-30 PerfektesChaos@de.wikipedia
var doc, props, socket;
if ( arglist ) {
doc = arglist[ 3 ];
socket = PAGES.fiat( doc );
if ( socket ) {
props = PAGES.windows[ socket ];
if ( props ) {
props.filepath = arglist[ 0 ];
PAGES.form( doc, socket );
PAGES.fill( doc, arglist[ 2 ] );
}
}
}
}; // IO.filled()
IO.find = function ( account, achieve, assign, add, allow ) {
// Find text file name
// Precondition:
// account -- sub path for: DBname / user name
// achieve -- pattern string
// assign -- suggestion for file name
// add -- suffix for new file, or false
// allow -- save a non-existing file
// Postcondition:
// Returns string with path, or false
// Uses:
// this
// > IO.search
// > IO.select
// > .locale.selectFile
// .prefs.getDirBase()
// .prefs.getDirSub()
// .fileIO.find()
// 2012-12-12 PerfektesChaos@de.wikipedia
var r,
pattern = [ "", achieve ],
start = PREFS.getDirBase(),
suffix = add,
suggest = assign;
if ( start && account ) {
start = start + PREFS.getDirSub( account );
}
if ( ! achieve ) {
pattern[ 1 ] = this.search;
}
if ( pattern[ 1 ] === this.search ) {
pattern[ 0 ] = this.select;
}
if ( suffix ) {
suffix = ( suffix === "*" ? "" : suffix );
} else {
suffix = "txt";
}
r = WLE.fileIO.find( start,
pattern,
suggest,
suffix,
WLE.locale.selectFile,
allow );
return r;
}; // IO.find()
IO.flush = function ( access, as ) {
// Write content into text file
// Precondition:
// access -- document of user edit web page
// as -- SaveAs file path, or false
// Postcondition:
// Returns true if failed
// Uses:
// this
// w
// > .pages.windows
// .pages.fiat()
// .pages.feed()
// .fileIO.flush()
// (IO.flushed)
// 2012-11-30 PerfektesChaos@de.wikipedia
var r,
socket = PAGES.fiat( access ),
store = ( as ? as : PAGES.windows[ socket ].filepath ),
story = PAGES.feed( access );
r = WLE.fileIO.flush( story,
store,
access,
this.flushed,
[ access, story, store, socket ] );
if ( r ) {
// Handle error!
w.alert( "IO.flush() " + r );
}
return r;
}; // IO.flush()
IO.flushed = function ( approve, arglist ) {
// Callback after asynchronous written text file
// Precondition:
// approve -- status code
// arglist -- Array
// Uses:
// w
// .pages.flushed()
// Remark: Used as event handler -- 'this' is not IO
// 2012-11-30 PerfektesChaos@de.wikipedia
if ( w.Components.isSuccessCode( approve ) ) {
PAGES.flushed( arglist[ 0 ],
arglist[ 1 ],
arglist[ 2 ],
arglist[ 3 ] );
} else {
w.alert( "IO.flushed() error=" + approve);
// Handle error!
}
}; // IO.flushed()
PAGES.feed = function ( access ) {
// Retrieve content from textarea
// Precondition:
// access -- document of user edit web page
// Postcondition:
// Returns text
// Uses:
// DOM.getElementById()
// 2012-11-30 PerfektesChaos@de.wikipedia
var elt = access.getElementById( "wpTextbox1" ),
r = false;
if ( elt ) {
r = elt.value;
}
return r;
}; // .pages.feed()
PAGES.fetch = function ( ask ) {
// Retrieve unique 64-bit ID number of user window
// Precondition:
// ask -- document of user web page
// Postcondition:
// Returns ID number string (tabbrowser window count)
// Uses:
// w
// 2012-11-30 PerfektesChaos@de.wikipedia
var cif,
util,
r = false,
win = ask.defaultView;
if ( win ) {
cif = w.Components.interfaces;
util = win.QueryInterface( cif.nsIInterfaceRequestor )
.getInterface( cif.nsIDOMWindowUtils );
if ( util ) {
r = "w#" + util.outerWindowID;
}
}
return r;
}; // .pages.fetch()
PAGES.fiat = function ( ask ) {
// Ensure persistent window information for this tabbrowser
// Precondition:
// ask -- document of user web page
// Postcondition:
// Returns ID number string
// Uses:
// this
// >< .pages.windows
// .pages.fetch()
// .pages.first()
// 2012-11-30 PerfektesChaos@de.wikipedia
var r = this.fetch( ask );
if ( r ) {
if ( ! this.windows ) {
this.windows = { };
}
if ( ! this.windows[ r ] ) {
this.first( r );
}
}
return r;
}; // .pages.fiat()
PAGES.file = function ( account, achieve, assign, access, ansi ) {
// If save, retrieve file name and content and put into textarea
// Precondition:
// account -- sub path for: DBname / user name
// achieve -- pattern string
// assign -- suffix for new file
// access -- document of user edit web page
// ansi -- input file is not utf-8
// Uses:
// this
// w
// > .pages.windows
// > .locale.saveFirst
// .pages.feed()
// .pages.fiat()
// IO.file()
// 2012-11-30 PerfektesChaos@de.wikipedia
var leeway = true,
screen = this.feed( access ),
socket,
store;
if ( screen ) {
socket = this.fiat( access );
store = this.windows[ socket ].wikitext;
if ( store ) {
leeway = ( screen === store );
if ( ! leeway ) {
w.alert( WLE.locale.saveFirst );
}
}
}
if ( leeway ) {
IO.file( account, achieve, assign, access, ansi );
}
}; // .pages.file()
PAGES.fill = function ( access, apply ) {
// Fill textarea with file content
// Precondition:
// access -- document of user edit web page
// apply -- content
// Uses:
// this
// < .pages.windows
// DOM.getElementById()
// DOM.createEvent()
// DOM.initEvent()
// DOM.dispatchEvent()
// .pages.fiat()
// 2012-11-30 PerfektesChaos@de.wikipedia
var elt = access.getElementById( "wpTextbox1" ),
event,
k,
socket,
story = apply;
if ( elt ) {
elt.value = story;
event = access.createEvent( "Events" );
event.initEvent( "wikilocaleditFilled", true, false );
elt.dispatchEvent( event );
// Byte Order Mark
k = story.charCodeAt(0);
if ( k === 255 ) {
if ( story.charCodeAt(1) === 254 ) {
story = story.substr( 2 );
}
} else if ( k === 65534 ) {
story = story.substr( 1 );
}
socket = this.fiat( access );
this.windows[ socket ].wikitext = story;
}
}; // .pages.fill()
PAGES.first = function ( assign ) {
// Initialize page window object
// assign -- windows ID
// Precondition:
// Uses:
// this
// < .pages.windows
// 2012-11-30 PerfektesChaos@de.wikipedia
this.windows[ assign ] = { filepath: false,
letwrite: true,
wikitext: false };
}; // .pages.first()
PAGES.flushed = function ( adjust, apply, address, assign ) {
// File content has been written
// Precondition:
// adjust -- document of static user page
// apply -- content
// address -- text file path
// assign -- windows ID
// Uses:
// this
// >< .pages.windows
// DOM.getElementById()
// DOM.createEvent()
// DOM.initEvent()
// DOM.dispatchEvent()
// .pages.setFile()
// 2012-11-30 PerfektesChaos@de.wikipedia
var elt = adjust.getElementById( "wpTextbox1" ),
event;
if ( elt ) {
event = adjust.createEvent("Events");
event.initEvent( "wikilocaleditSaved", true, false );
elt.dispatchEvent( event );
this.windows[ assign ].wikitext = apply;
PAGES.windows[ assign ].filepath = address;
this.setFile( adjust, address );
}
}; // .pages.flushed()
PAGES.form = function ( adjust, aim ) {
// Decorate edit/submit user page of /LocalEdit
// Precondition:
// adjust -- document of static user page
// aim -- unique window identifier
// Uses:
// this
// > .pages.windows
// .pages.setFile()
// 2012-12-12 PerfektesChaos@de.wikipedia
var elt = adjust.getElementById( "WLE_select_SaveFile" ),
props = this.windows[ aim ],
s = props.filepath;
if ( elt ) {
if ( s ) {
this.setFile( adjust, s );
elt.disabled = ! props.letwrite;
} else {
this.setFile( adjust, "" );
elt.disabled = true;
}
}
}; // .pages.form()
PAGES.fresh = function () {
// Update userpage list and page URL listener
// Uses:
// this
// >< .pages.userURLstatics
// >< .pages.userURLsubmits
// .prefs.getUserlist()
// Remark: Used by content/config.js
// 2012-11-30 PerfektesChaos@de.wikipedia
var i, j, n, s, s0, s1, sift, site,
userlist = WLE.prefs.getUserlist();
if ( userlist ) {
n = userlist.length;
this.userURLstatics = new Array( n );
this.userURLsubmits = new Array( n );
for ( i = 0; i < n; i++ ) {
s = userlist[ i ];
j = s.indexOf( "/wiki/" );
if ( j > 15 ) {
site = s.substr( 0, j + 1 );
sift = s.substr( j + 6 ) + "/LocalEdit";
s0 = site + "wiki/" + sift;
s1 = site + "w/index.php?title=" + sift
+ "&action=";
} else {
s0 = "";
s1 = "";
}
this.userURLstatics[ i ] = s0;
this.userURLsubmits[ i ] = s1;
} // for i
} else if ( this.userURLstatics ) {
delete this.userURLstatics;
delete this.userURLsubmits;
}
}; // .pages.fresh()
PAGES.furnish = function ( adjust ) {
// Decorate static user page of /wiki/ /LocalEdit
// Precondition:
// adjust -- document of static user page
// Uses:
// this
// DOM.getElementById()
// DOM.setAttribute()
// .pages.setDirBase()
// .pages.setDirSub()
// 2012-11-30 PerfektesChaos@de.wikipedia
var elt, s, specific;
elt = adjust.getElementById( "WLE.inactive" );
elt.setAttribute( "style", "display:none" );
elt = adjust.getElementById( "WLE.active" );
elt.removeAttribute( "style" );
elt = adjust.getElementById( "WLE.client" );
s = elt.getAttribute( "src" );
elt = adjust.getElementById( "WLE.stateIMG" );
elt.setAttribute( "src", s );
this.setDirBase( adjust );
elt = adjust.getElementById( "WLE.DirBase" );
elt.removeAttribute( "style" );
elt = adjust.getElementById( "WLE.specific" );
specific = elt.textContent;
this.setDirSub( adjust, specific );
elt = adjust.getElementById( "WLE.startEdit" );
elt.removeAttribute( "style" );
}; // .pages.furnish()
PAGES.isPageUser = function ( approve ) {
// Check whether event has been launched from registered user page
// Precondition:
// approve -- document to be checked for origin
// Postcondition:
// Returns Array iff dispatched from requested user page
// [0] document
// [1] false: static, else dynamic action
// Uses:
// this
// > .reDomain
// > .pages.userURLstatics
// > .pages.userURLsubmits
// 2012-11-30 PerfektesChaos@de.wikipedia
var i, n, doc, s, src,
r = false;
if ( this.userURLstatics ) {
doc = approve;
if ( doc instanceof HTMLDocument ) {
// is this an inner frame?
if ( doc.defaultView.frameElement ) {
// Frame within a tab was loaded.
// Find the root document:
while ( doc.defaultView.frameElement ) {
doc = doc.defaultView.frameElement.ownerDocument;
}
}
}
src = doc.URL;
if ( WLE.reDomain.test( src ) ) {
n = this.userURLstatics.length;
for ( i = 0; i < n; i++ ) {
if ( src === this.userURLstatics[ i ] ) {
r = [ doc, false ];
break;
}
} // for i
if ( ! r ) {
for ( i = 0; i < n; i++ ) {
s = this.userURLsubmits[ i ];
if ( src.indexOf( s ) === 0 ) {
r = [ doc, src.substr( s.length ) ];
break;
}
} // for i
}
}
}
return r;
}; // .pages.isPageUser()
PAGES.setDirBase = function ( adjust ) {
// Write base directory path into static /LocalEdit user page
// Precondition:
// adjust -- document of static user page
// Postcondition:
// Returns base directory
// Uses:
// DOM.getElementById()
// .prefs.getDirBase()
// 2012-11-30 PerfektesChaos@de.wikipedia
var elt = adjust.getElementById( "WLE.dirbase" ),
r = PREFS.getDirBase();
if ( elt ) {
elt.textContent = r;
}
return r;
}; // .pages.setDirBase()
PAGES.setDirSub = function ( adjust, account ) {
// Write project directory path into static /LocalEdit user page
// Precondition:
// adjust -- document of static user page
// account -- DBname . user name
// Uses:
// DOM.getElementById()
// .prefs.getDirBase()
// DOM.removeAttribute()
// DOM.setAttribute()
// 2012-11-30 PerfektesChaos@de.wikipedia
var eltButt = adjust.getElementById( "WLE.DirSub" ),
eltPath = adjust.getElementById( "WLE.dirsub" );
if ( eltButt && eltPath ) {
if ( PREFS.getDirBase() ) {
eltButt.removeAttribute( "style" );
eltPath.removeAttribute( "style" );
eltPath.textContent = PREFS.getDirSub( account );
} else {
eltButt.setAttribute( "style", "display:none" );
eltPath.setAttribute( "style", "display:none" );
}
}
}; // .pages.setDirSub()
PAGES.setFile = function ( adjust, address ) {
// Write text file path into user page
// Precondition:
// adjust -- document of static user page
// address -- text file path
// Uses:
// DOM.getElementById()
// DOM.setAttribute()
// 2012-11-30 PerfektesChaos@de.wikipedia
var elt = adjust.getElementById( "LocalEditFilePath" ),
style;
if ( elt ) {
if ( address ) {
elt.textContent = address;
style = "margin-bottom: 1em;"
+ "border-bottom: solid 2px #0000FF;";
} else {
style = "display:none";
}
elt = adjust.getElementById( "LocalEditFileDiv" );
elt.setAttribute( "style", style );
}
}; // .pages.setFile()
WLE.toolBarClicked = function () {
// Button on panel has been clicked.
// Start or stop listening on events.
// Uses:
// >< .live
// TOOL.fresh()
// Remark: Used as event handler -- 'this' is not WLE
// 2012-11-30 PerfektesChaos@de.wikipedia
WLE.live = ! WLE.live;
TOOL.fresh( false );
}; // .toolBarClicked()
TOOL.fresh = function ( all ) {
// Update toolbar menu state
// Uses:
// this
// > TOOL.panelButton
// > .live
// DOM.getElementById()
// EVENTS.fresh()
// 2012-11-30 PerfektesChaos@de.wikipedia
var show;
if ( ! this.panelButton ) {
this.panelButton
= document.getElementById( "wikilocaleditToolbarbutton" );
}
if ( this.panelButton ) {
show = "chrome://wikilocaledit/skin/wikilocaledit-24" + "x24"
+ ( WLE.live ? "" : "-off" ) + ".png";
this.panelButton.image = show;
if ( all ) {
this.panelButton.tooltipText = "";
}
}
EVENTS.fresh();
}; // TOOL.fresh()
} ( window ) );
/// EOF </nowiki> content/wikilocaledit.js