Line 1: |
Line 1: |
| // License: GPL | | // License: GPL |
− | // Indexeddb JavaScript | + | // User Interface Rendering |
− | console.log('Indb loading'); | + | console.log('Interface handler loading'); |
| | | |
− | function IndexedDBContainer( ww ) { | + | function InterfaceMediaContainer ( WikibaseProcessor, indexedDBobject ) { |
− | | |
− | // suppress console.log, switch to true for debug
| |
− | var Debug_switch = false;
| |
| | | |
− | // deterministic hash generator for creating user id#s from usernames, should be replaced by something more functional (guaranteed to be transitively different) | + | this.renderInterface = function( sqitch ) { |
− | hashCode = function(s) {
| + | switch( sqitch ) { |
− | if ( s == undefined) { | + | case 'controller_id': |
− | s = '00' | + | controller_render(); |
| + | break; |
| + | case 'personal_data_id': |
| + | pd_site_render(); |
| + | break; |
| + | case 'interface_button_id': |
| + | personal_data_edit_interface_render(); |
| + | break; |
| } | | } |
− | var h = 0, l = s.length, i = 0;
| + | } |
− | if ( l > 0 )
| |
− | while (i < l)
| |
− | h = (h << 5) - h + s.charCodeAt(i++) | 0;
| |
− | return h;
| |
− | };
| |
| | | |
− | | + | var button_save = [], |
− | if ( ww.user != undefined ) { | + | button_remove = [], |
− | // if user exists in object passed to constructor, get username
| + | textInput = []; |
− | var self = ww.user.getName();
| |
− | // create userid by hashing username
| |
− | var idgen = hashCode(self);
| |
− | debuglog(idgen);
| |
| | | |
− | // Take username for standard databasename format:
| + | async function controller_render(){ |
− | // Our current convention for personal databasename (separate dbname for each user)
| + | console.log("this function is done by the current page controller for now"); |
− | var PersonalDataDataBaseName = "PD.IO" + idgen + "Database";
| + | notify_porting(); |
− | // Use username in user to get up to date version of self
| |
− | // Blank object for personal data Record with id and username included
| |
− | this.CurrentPerson = {id: idgen, name: {user: self}, age: 0};
| |
− | debuglog(PersonalDataDataBaseName);
| |
− | debuglog(this.CurrentPerson);
| |
− | }
| |
− | | |
− | // ADD MORE DOC | |
− | | |
− | // EnqueuePDIO a PDIOLocalDatabase:User database access function with modes
| |
− | // Externally accessible wrapper for Enquire with current user / db preloaded
| |
− | | |
− | this.EnqueuePDIO = async function( sw, c1, c2, c3 ) {
| |
− | var k = await Enquire( PersonalDataDataBaseName, this.CurrentPerson, sw, c1, c2, c3 ); | |
− | return k; | |
| } | | } |
| | | |
− | // Enquire, a general purpose indexeddb update function with modes | + | async function pd_site_render(){ |
| | | |
− | // Mode 'aggressive push': | + | }; |
− | // parameter record is pushed to database, overwriting whatever is there
| |
| | | |
− | // Mode 'checkin': | + | async function personal_data_edit_interface_render(){ |
− | // record is retrieved from database, parameter record is pushed if not found
| + | clear_render(); |
| + | |
| + | // Get concerns relation :: Parts of this must be moved upstream, MAIN should know that this is the data the renderer will need and provide it |
| | | |
− | // Mode 'get record'
| + | var concern_origin = WikibaseProcessor.checkentity( { this_concerns: [ WBEStructure['concernsRelation'], WBEStructure['IDPropLoc'], WBEStructure['qIDPropName'] ] } )['this_concerns'][0]; |
− | // updates record given as argument
| |
| | | |
− | // Mode 'update record' field1 field2 field3
| + | // Get defval for entity :: Parts of this must be moved upstream, MAIN should know that this is the data the renderer will need and provide it |
− | // retrieve record, make record.field1.field2 = field3, push back
| |
| | | |
− | // Mode 'update record' field1 field2
| + | var default_value = WikibaseProcessor.checkentity( { default_value: [ WBEStructure['defaultValRelation'], WBEStructure['IDPropLoc'] ] } )['default_value'][0]; //defal |
− | // retrieve record, make record.field1 = field2, push back
| |
| | | |
− | // Mode 'remove from record' field1
| + | var get_record = indexedDBobject.EnqueuePDIO('update record'); |
− | // retrieve record, splice/delete record.field1, push back
| |
− |
| |
− | // Mode 'remove from record' field1 field2
| |
− | // retrieve record, splice/delete record.field1.field2, push back
| |
| | | |
− | async function Enquire( pddbname, record, sqitch, control_1, control_2, control_3 ) {
| + | get_record.then( function(result) { |
− | return new Promise( | |
− | function(resolve, reject) {
| |
| | | |
− | var pddb = window.indexedDB.open(pddbname, 3);
| + | mw.loader.using( 'oojs-ui-core' ).done( function () { |
− | var inp_obj;
| |
| | | |
− | // indexeddb internal mechanism for version tracking of schema | + | button_save = [], |
− | pddb.onupgradeneeded = function() { | + | button_remove = [], |
− | console.log('upgrading database');
| + | textInput = []; |
− | var db = pddb.result;
| |
− | var store = db.createObjectStore(pddbname, {keyPath: "id"});
| |
| | | |
− | // shouldn't the index be the wiki.personaldata.io username?
| + | var extrafield = ( result[concern_origin] != undefined ) ? Object.keys(result[concern_origin]).length : 0; |
| | | |
− | var index = store.createIndex("NameIndex", ["id"]);
| + | button_save[ extrafield ] = new OO.ui.ButtonWidget( { label: "Save", classes: [ 'pduimark' ] } ); |
− | }; | + | |
− | // Database successfully opened function. | + | textInput[ extrafield ] = new OO.ui.TextInputWidget( { |
− | pddb.onsuccess = function() {
| + | placeholder: default_value, |
− | var db = pddb.result;
| + | classes: [ 'pduimark' ] |
− | var tx = db.transaction(pddbname, "readwrite");
| + | } ); |
− | var store = tx.objectStore(pddbname);
| |
− | var index = store.index("NameIndex");
| |
| | | |
− | // Get the original record from the db...
| + | button_save[ extrafield ].on( 'click', function () { |
− | var getRecord = index.get([record.id]);
| + | indexedDBobject.EnqueuePDIO('update record', concern_origin, extrafield, textInput[ extrafield ].value ); |
| + | personal_data_edit_interface_render(); |
| + | }); |
| | | |
− | getRecord.onsuccess = function() {
| + | $( '#mw-content-text' ).prepend( button_save[ extrafield ].$element ); |
− | debuglog( "Record found in database: \n <<");
| + | $( '#mw-content-text' ).prepend( textInput[ extrafield ].$element ); |
− | debuglog( getRecord.result );
| |
− | debuglog( ">>");
| |
− | // Essential recordAdd
| |
− | if ( sqitch === "aggressive push" ) {
| |
− | // Mode 'aggressive push':
| |
− | // parameter record is pushed to database, overwriting whatever is there
| |
− | inp_obj = record;
| |
− | store.put( inp_obj );
| |
− | return inp_obj;
| |
− | } else if ( sqitch === "checkin" ) {
| |
− | // Mode 'checkin':
| |
− | // record is retrieved from database, parameter record is pushed if not found
| |
− | if ( getRecord.result != undefined ) {
| |
− | debuglog("getting from store");
| |
− | inp_obj = getRecord.result;
| |
− | } else {
| |
− | debuglog("overriding whatever in there");
| |
− | inp_obj = record;
| |
− | store.put(inp_obj);
| |
− | }
| |
| | | |
− | } else {
| + | if ( extrafield > 0) { |
− | // Methods manipulationg the actual record come here
| + | Object.keys( result[concern_origin] ).forEach( function(data) { |
− | // Update & Remove from
| + | button_save[data] = new OO.ui.ButtonWidget( { label: "Save", classes: [ 'pduimark' ] } ); |
− | // If we got the record from store, use that version to be manipulated
| + | button_remove[data] = new OO.ui.ButtonWidget( { label: "Delete", classes: [ 'pduimark' ] } ); |
− | if ( getRecord.result != undefined ) {
| + | textInput[data] = new OO.ui.TextInputWidget( { |
− | inp_obj = getRecord.result;
| + | value: result[concern_origin][data], /// |
− |
| + | placeholder: default_value, |
− | if ( sqitch === "get record" ) {
| + | classes: [ 'pduimark' ] |
− |
| + | } ); |
− | debuglog("Getting record");
| + | button_save[data].on( 'click', function () { |
− | // we will return later
| |
− |
| |
− | }
| |
| | | |
− | // endof onsuccess
| + | indexedDBobject.EnqueuePDIO('update record', concern_origin, data, textInput[ data ].value ); |
− | } else { | |
| | | |
− | debuglog("Record not found");
| + | personal_data_edit_interface_render(); |
| + | }); |
| | | |
− | if ( sqitch === "update record" ) {
| + | button_remove[data].on( 'click', function () { |
− | // Update record will use supplied copy to update it
| + | indexedDBobject.EnqueuePDIO('remove from record', concern_origin, data ); |
− | inp_obj = record;
| + | personal_data_edit_interface_render(); |
− | } else {
| + | }); |
− | // Remove from record will quit as record was not even found
| + | $( '#mw-content-text' ).prepend( button_remove[data].$element ); |
− | return undefined;
| + | $( '#mw-content-text' ).prepend( button_save[data].$element ); |
− | }
| + | $( '#mw-content-text' ).prepend( textInput[data].$element ); |
− | }
| |
− | } | |
| | | |
− | if ( sqitch === "update record" ) { // Record Update
| + | }); |
− | if ( control_1 != undefined ) {
| |
− | if ( control_2 != undefined ) {
| |
− | if ( control_3 != undefined ) {
| |
| | | |
− | // Mode 'update record' field1 field2 field3
| + | } |
− | // retrieve record, make record.field1.field2 = field3, push back | + | }); |
| + | }); |
| + | }; |
| | | |
− | if ( inp_obj[ control_1 ] == undefined ) { inp_obj[ control_1 ] = (isNaN( control_2 )) ? {} : [] };
| + | function clear_render() { |
− | inp_obj[ control_1 ][ control_2 ] = control_3; // => "Bob"
| + | var ifel = document.getElementsByClassName('pduimark'); |
− | store.put(inp_obj);
| + | while( ifel[0] ) { |
− | } else {
| + | ifel[0].parentNode.removeChild(ifel[0]); |
| + | }; |
| + | }; |
| + | |
| + | function notify_porting() { |
| | | |
− | // Mode 'update record' field1 field2
| + | mw.loader.using( 'oojs-ui-core' ).done( function () { |
− | // retrieve record, make record.field1 = field2, push back
| |
| | | |
− | inp_obj[ control_1 ] = inp_obj[ control_1 ] || {};
| + | var button_import = new OO.ui.SelectFileWidget( { label: "Import Personal Data", classes: [ 'pduimark' ] } ), |
− | if ( Array.isArray( inp_obj[ control_1 ] ) ) {
| |
− | inp_obj[ control_1 ].push( control_2 );
| |
− | } else {
| |
− | inp_obj[ control_1 ] = control_2;
| |
− | }
| |
− | store.put(inp_obj);
| |
| | | |
− | }
| + | button_export = new OO.ui.ButtonWidget( { label: "Export Personal Data", classes: [ 'pduimark' ] } ); |
− | } else {
| |
− | // Only one control defined. We will return that part of the record, and change nothing
| |
− | inp_obj = inp_obj[ control_1 ];
| |
− | }
| |
− | } else {
| |
| | | |
− | // There's not even control_1, we will just return the record itself
| + | button_import.on( 'change', function (event) { |
| | | |
− | }
| + | if (window.webkitURL != null) { |
− | debuglog("return 3")
| + | console.log("loading file on webkit") |
− | // return inp_obj;
| + | } else { |
| + | console.log("loading file non webkit") |
| + | } |
| | | |
− | };
| + | console.log( event ); |
| | | |
− | if ( sqitch === "remove from record" ) { // Record Update
| + | }); |
− | if ( control_1 != undefined ) {
| |
− | if ( control_2 != undefined ) {
| |
| | | |
− | // Mode 'remove from record' field1 field2
| + | button_export.on( 'click', function () { |
− | // retrieve record, splice/delete record.field1.field2, push back
| |
− |
| |
− | if ( Array.isArray( inp_obj[ control_1 ] ) && !isNaN( control_2 ) ) {
| |
− | inp_obj[ control_1 ].splice( control_2, 1 );
| |
− | } else {
| |
− | delete inp_obj[ control_1 ][ control_2 ];
| |
− | }
| |
| | | |
− | } else {
| + | var get_record = indexedDBobject.EnqueuePDIO('get record'); |
| | | |
− | // Mode 'remove from record' field1
| + | get_record.then( function(result) { |
− | // retrieve record, splice/delete record.field1, push back
| + | console.log("happening"); |
| + | if ( result === undefined ) { window.alert("No local data to export") } else { |
| | | |
− | delete inp_obj[ control_1 ];
| + | var filename_tosaveas = "pdiolocalexport_" + result.name.user + "_" + Date.now() + '.json'; |
− | }
| + | |
− | } | + | result.id = ''; |
− | store.put(inp_obj); | + | result.name.user = ''; |
| + | |
| + | var export_to_text = JSON.stringify(result); |
| + | var textFileAsBlob = new Blob([export_to_text], {type:'text/plain'}); |
| + | var downloadLink = document.createElement("a"); |
| + | downloadLink.download = filename_tosaveas; |
| + | if (window.webkitURL != null) |
| + | { |
| + | // Chrome allows the link to be clicked |
| + | // without actually adding it to the DOM. |
| + | downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob); |
| + | } |
| + | else |
| + | { |
| + | // Firefox requires the link to be added to the DOM |
| + | // before it can be clicked. |
| + | downloadLink.href = window.URL.createObjectURL(textFileAsBlob); |
| + | downloadLink.style.display = "none"; |
| + | document.body.appendChild(downloadLink); |
| } | | } |
| | | |
− | // We are past all methodic code, Async return
| + | downloadLink.click(); |
− |
| + | |
− | resolve( inp_obj ); | + | } |
| | | |
− | };
| + | }); |
− |
| |
− | // Indexeddb internal mechanism, close db
| |
− |
| |
− | tx.oncomplete = function() {
| |
− | debuglog("return 1")
| |
− | db.close();
| |
− | };
| |
− | };
| |
− | debuglog("return 0")
| |
| | | |
− | // End of promise
| |
− |
| |
− | }).then( function(result) {
| |
− | debuglog("Mark 3");
| |
− | debuglog(result);
| |
− | return result;
| |
| }); | | }); |
| + | |
| + | mw.notify( $( button_import.$element ), { autoHide: false } ); |
| + | mw.notify( $( button_export.$element ), { autoHide: false } ); |
| + | }); |
| } | | } |
| | | |
− | function debuglog( l0g ){
| + | } |
− | if ( Debug_switch ) {
| |
− | debuglog( l0g );
| |
− | }
| |
− | }
| |
− | };
| |