Edit: Save compiled HTML when editing pages [#699]

staging
gnosygnu 4 years ago
parent dc374fa7fc
commit 0aced904a5

@ -1,309 +1,310 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.guis.views;
import gplx.Bry_;
import gplx.Bry_find_;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.Gfo_evt_mgr_;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.Gfo_usr_dlg;
import gplx.GfsCtx;
import gplx.Int_;
import gplx.List_adp;
import gplx.String_;
import gplx.core.envs.Env_;
import gplx.core.threads.Gfo_thread_wkr;
import gplx.gfui.controls.elems.GfuiElem;
import gplx.gfui.controls.elems.GfuiElemKeys;
import gplx.gfui.controls.standards.Gfui_html;
import gplx.gfui.controls.standards.Gfui_tab_itm;
import gplx.gfui.controls.standards.Gfui_tab_itm_data;
import gplx.gfui.ipts.IptBnd_;
import gplx.gfui.ipts.IptCfg_;
import gplx.gfui.ipts.IptEventType_;
import gplx.gfui.ipts.IptKey_;
import gplx.gfui.ipts.IptMouseBtn_;
import gplx.gfui.kits.core.Gfui_kit;
import gplx.xowa.Xoa_app;
import gplx.xowa.Xoa_page;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoa_url_;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xow_wiki;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.files.Xof_file_wkr;
import gplx.xowa.files.Xog_redlink_thread;
import gplx.xowa.guis.Xoa_gui_mgr;
import gplx.xowa.guis.bnds.Xog_bnd_box_;
import gplx.xowa.guis.history.Xog_history_mgr;
import gplx.xowa.wikis.pages.Xopg_view_mode_;
public class Xog_tab_itm implements Gfo_invk {
private Xog_win_itm win;
public Xog_tab_itm(Xog_tab_mgr tab_mgr, Gfui_tab_itm_data tab_data, Xowe_wiki wiki, Xoae_page page) {
this.tab_mgr = tab_mgr; this.tab_data = tab_data; this.wiki = wiki; this.page = page;
this.win = tab_mgr.Win();
this.html_itm = new Xog_html_itm(this);
cmd_sync = win.Kit().New_cmd_sync(this);
}
public Xowe_wiki Wiki() {return wiki;} public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki;
public Gfo_invk Cmd_sync() {return cmd_sync;} private Gfo_invk cmd_sync;
public void Make_html_box(int uid, Gfui_tab_itm tab_box, Xog_win_itm win, GfuiElem owner) {
this.tab_box = tab_box;
Xoae_app app = win.App(); Xoa_gui_mgr gui_mgr = win.Gui_mgr(); Gfui_kit kit = win.Kit();
Gfui_html html_box = kit.New_html("html_box" + Int_.To_str(uid), owner);
html_box.Html_js_enabled_(tab_mgr.Javascript_enabled());
html_box.Html_invk_src_(win);
html_itm.Html_box_(html_box);
if (app.Mode().Tid_is_gui()) { // NOTE: only run for gui; will cause firefox_addon to fail; DATE:2014-05-03
// NOTE: must set source, else control will be empty, and key events will not be raised; DATE:2014-04-30
// NOTE: use load_by_url for nightmode else load_by_mem causes "white flashing" DATE:2017-03-04
if (app.Gui_mgr().Nightmode_mgr().Enabled()) {
html_box.Html_doc_html_load_by_url
( app.Usere().Fsys_mgr().App_temp_html_dir().GenSubFil("tab_new.html")
, String_.new_u8(gplx.xowa.specials.xowa.default_tab.Default_tab_page.DEFAULT_HTML_NIGHT)
);
}
else {
html_box.Html_doc_html_load_by_mem("");
}
IptBnd_.ipt_to_(IptCfg_.Null, html_box, this, "popup", IptEventType_.MouseDown, IptMouseBtn_.Right);
IptBnd_.cmd_to_(IptCfg_.Null, html_box, win, Xog_win_itm.Invk_exit, IptKey_.add_(IptKey_.Alt, IptKey_.F4)); // WORKAROUND:SWT: xulrunner_v24 no longer sends Alt+F4 to SwtShell; must manually subscribe it to quit; DATE:2015-07-31
Gfo_evt_mgr_.Sub_same(html_box, GfuiElemKeys.Evt_menu_detected, html_itm);
gui_mgr.Bnd_mgr().Bind(Xog_bnd_box_.Tid_browser_html, html_box);
if (!Env_.Mode_testing())
kit.Set_mnu_popup(html_box, gui_mgr.Menu_mgr().Popup().Html_page().Under_mnu());
}
}
public void Switch_mem(Xog_tab_itm comp) {
// switch html_itm.owner_tab reference only
html_itm.Switch_mem(comp.html_itm);
// switch .html_itm, since the underlying CTabFolder has reparented the control
Xog_html_itm temp_html_itm = html_itm;
this.html_itm = comp.html_itm;
comp.html_itm = temp_html_itm;
// switch .page, since its underlying html_box has changed and .page must reflect html_box
Xoae_page temp_page = page;
this.page = comp.page;
comp.page = temp_page;
page.Tab_data().Tab_(this); comp.Page().Tab_data().Tab_(comp);
// switch .wiki also; ISSUE#:761; DATE:2020-07-17
Xowe_wiki temp_wiki = wiki;
this.wiki = comp.wiki;
comp.wiki = temp_wiki;
// switch .view_mode to match .page
byte temp_view_mode = view_mode;
this.view_mode = comp.view_mode;
comp.view_mode = temp_view_mode;
// switch .history_mgr along with .page
Xog_history_mgr temp_history_mgr = history_mgr;
this.history_mgr = comp.history_mgr;
comp.history_mgr = temp_history_mgr;
}
public Gfui_tab_itm_data Tab_data() {return tab_data;} private Gfui_tab_itm_data tab_data;
public String Tab_key() {return tab_data.Key();}
public int Tab_idx() {return tab_data.Idx();} public void Tab_idx_(int v) {tab_data.Idx_(v);}
public Xog_tab_mgr Tab_mgr() {return tab_mgr;} private Xog_tab_mgr tab_mgr;
public Gfui_tab_itm Tab_box() {return tab_box;} private Gfui_tab_itm tab_box;
public boolean Tab_is_loading() {return tab_is_loading;} private boolean tab_is_loading;
public Xog_html_itm Html_itm() {return html_itm;} private Xog_html_itm html_itm;
public Gfui_html Html_box() {return html_itm.Html_box();}
public Xoae_page Page() {return page;}
public void Page_ref_(Xoae_page v) {
this.page = v;
this.wiki = page.Wikie(); // NOTE: must update wiki else back doesn't work; DATE:2015-03-05
}
public void Page_(Xoae_page page) {
Page_ref_(page);
this.Page_update_ui(); // force tab button to update when page changes
} private Xoae_page page;
public void Page_update_ui() {
this.Tab_name_();
tab_box.Tab_tip_text_(page.Url().To_str());
}
public void Tab_name_() {
byte[] tab_name = page.Html_data().Custom_tab_name(); // Custom_tab_name set by Special:Default_tab or variants; DATE:2015-10-05
if (tab_name == null) tab_name = page.Ttl().Full_txt(); // no custom_tab_name; use ttl's text
Tab_name_(String_.new_u8(tab_name));
}
public void Tab_name_(String tab_name) {
tab_name = Xog_tab_itm_.Tab_name_min(tab_name, tab_mgr.Btns__min_chars());
tab_name = Xog_tab_itm_.Tab_name_max(tab_name, tab_mgr.Btns__max_chars());
tab_box.Tab_name_(tab_name);
}
public Xog_history_mgr History_mgr() {return history_mgr;} private Xog_history_mgr history_mgr = new Xog_history_mgr();
public byte View_mode() {return view_mode;} private byte view_mode = Xopg_view_mode_.Tid__read;
public void View_mode_(byte v) {
view_mode = v;
if (view_mode != Xopg_view_mode_.Tid__read) // if read, don't bother adding "action=read"
page.Url().Qargs_mgr().Set_val_by_bry(Xoa_url_.Qarg__action, Xopg_view_mode_.To_bry(v));
}
public void Pin_toggle() {}
public void Show_url_bgn(Xoa_url url) {
this.tab_is_loading = true;
Xoae_app app = win.App(); Gfo_usr_dlg usr_dlg = app.Usr_dlg();
// get new_tab_name
this.wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_make_init_y(url.Wiki_bry()); // NOTE: must go before wiki.Props().Main_page(); DATE:2016-08-02; NOTE: must load wiki; DATE:2015-07-22
if (url.Page_is_main()) url.Page_bry_(wiki.Props().Main_page()); // NOTE: must go before ttl.Make; DATE:2016-07-31
Xoa_ttl ttl = wiki.Ttl_parse(url.Page_bry());
if (ttl == null) {usr_dlg.Prog_one("", "", "title is invalid: ~{0}", String_.new_u8(url.Raw())); return;}
String new_tab_name = String_.new_u8(ttl.Full_txt());
// if clicking on anchor, just scroll; do not load page
if ( url.Anch_str() != null // url has anchor
&& url.Eq_page(page.Url()) // url has same page_name as existing page
&& url.Qargs_ary().length == 0 // url has no args; needed for Category:A?from=b#mw-pages
&& String_.Eq(new_tab_name, tab_data.Name()) // NOTE: name will be null / empty when starting app and last session had page with #anchor; EX:Main_Page#Links; DATE:2016-07-21
) {
html_itm.Scroll_page_by_id_gui(url.Anch_str());
return;
}
if (win.Page__async__working(url)) return;
if (page != null) page.Tab_data().Close_mgr().When_close(this, url); // cancel any current search cmds
app.Log_wtr().Queue_enabled_(true);
usr_dlg.Gui_wkr().Clear();
if (url.Vnt_bry() != null) {
byte[] vnt = url.Vnt_bry();
if (!Bry_.Eq(vnt, wiki.Lang().Vnt_mgr().Cur_itm().Key()))
wiki.Appe().Cfg().Set_bry_wiki(wiki, Xowe_wiki.Cfg__variant__current, vnt);
}
Tab_name_(new_tab_name);
usr_dlg.Prog_one("", "", "loading: ~{0}", String_.new_u8(ttl.Raw()));
// DELETE: no longer seems needed; popups always disappear when navigating to new page; DATE:2018-11-11
// if (wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled())
// this.Html_box().Html_js_eval_script("if (window.xowa_popups_hide_all != null) window.xowa_popups_hide_all();"); // should be more configurable; DATE:2014-07-09
app.Thread_mgr_old().Page_load_mgr().Add_at_end(new Load_page_wkr(this, wiki, url, ttl)).Run();
}
private void Show_url_loaded(Load_page_wkr wkr) {
Xowe_wiki wiki = wkr.Wiki(); Xoae_page page = wkr.Page();
Xoa_url url = page.Url(); Xoa_ttl ttl = page.Ttl();
Xoae_app app = wiki.Appe(); Gfo_usr_dlg usr_dlg = app.Usr_dlg();
try {
if (page.Tab_data().Cancel_show()) return; // Special:Search canceled show; NOTE: must be inside try b/c finally handles thread
wiki.Parser_mgr().Ctx().Page_(page);
if ( page.Db().Page().Exists_n()
&& !page.Commons_mgr().Xowa_mockup()) { // do not enter "missing" section if File_mockup; EX:en.wikipedia.org/wiki/File:Protoplanetary-disk.jpg DATE:2016-11-13
if (wiki.Db_mgr().Save_mgr().Create_enabled()
|| wiki.Page_mgr().Sync_mgr().Auto_enabled()) {
page = Xoae_page.New_edit(wiki, ttl);
page.Url_(url); // NOTE: need to set url else query args like action=edit will be lost; DATE:2019-03-20
view_mode = Xopg_view_mode_.Tid__edit;
history_mgr.Add(page); // NOTE: must put new_page on stack so that pressing back will pop new_page, not previous page
Xog_tab_itm_read_mgr.Show_page(this, page, false);
}
else {
wkr.Page().Tab_data().Tab().Page_(page); // NOTE: must set tab's page to current page, so that switching to it will update url bar; EX:pt.b:A"MANUAL_DE_PROCEDURI_.Sectiunea:""CONTABILITATE_SI_MANAGEMENT_FINANCIAR""" DATE:2015-09-17
if (page.Redirect_trail().Itms__len() > 0)
usr_dlg.Prog_many("", "", "could not find page in wiki: ~{0} (redirected from ~{1})", String_.new_u8(page.Url().Page_bry()), page.Redirect_trail().Itms__get_at_0th_or_null());
else {
if (ttl.Ns().Id_is_file())
usr_dlg.Prog_one("", "", "commons.wikimedia.org must be installed in order to view the file. See [[App/Wiki_types/Commons]]: ~{0}", String_.new_u8(url.Raw()));// HOME
else
usr_dlg.Prog_one("", "", "could not find page in wiki: ~{0}", String_.new_u8(url.Raw()));
}
}
app.Log_wtr().Queue_enabled_(false);
return;
}
// if (!page.Redirected()) page.Url_(url); // NOTE: handle redirect from commons; COMMENTED: part of redirect rewrite; DATE:2016-07-05
if (page.Ttl().Anch_bgn() != Bry_find_.Not_found) page.Url().Anch_bry_(page.Ttl().Anch_txt()); // NOTE: occurs when page is a redirect to an anchor; EX: w:Duck race -> Rubber duck#Races
history_mgr.Add(page);
Xog_tab_itm_read_mgr.Show_page(this, page, true);
if (app.Usere().History_mgr().Enabled()) {
app.Usere().History_mgr().Add(page);
app.User().User_db_mgr().History_mgr().Update_async(app.Async_mgr(), ttl, url);
}
usr_dlg.Prog_none("", "", "rendering html");
// html_itm.Html_box().Size_(tab_mgr.Tab_mgr().Size()); // COMMENTED: causes clicks on macosx to be off by 4 px; NOTE: must resize tab here, else scrolling to anchor in background tab doesn't work (html_box has size of 0, 0) DATE:2015-05-03
// win.Page__async__bgn(this);
Gfo_thread_wkr async_wkr = null;
if (page.Html_data().Hdump_exists()) {
// wiki.File_mgr().Init_file_mgr_by_load(wiki);
// Xof_fsdb_mgr fsdb_mgr = wiki.File_mgr().Fsdb_mgr();
// async_wkr = new Xof_file_wkr(wiki.File__orig_mgr(), fsdb_mgr.Bin_mgr(), fsdb_mgr.Mnt_mgr(), app.Usere().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, page.Hdump_mgr().Imgs());
async_wkr = new Load_files_wkr(this);
if (wiki.Html__hdump_enabled() && page.Db().Page().Html_db_id() == -1) {
wiki.Html__hdump_mgr().Save_mgr().Save(page);
}
}
else
async_wkr = new Load_files_wkr(this);
page.Html_data().Mode_wtxt_shown_y_();
app.Thread_mgr_old().File_load_mgr().Add_at_end(async_wkr).Run();
// app.Thread_mgr().Get_by_or_new("on_page_load").Add(new Xopg_img_thread(), new Xopg_rl_thread());
}
finally {
app.Thread_mgr_old().Page_load_mgr().Resume();
this.tab_is_loading = false;
}
}
public void Exec_async_hdump(Xoa_app app, Xow_wiki wiki, gplx.xowa.guis.cbks.js.Xog_js_wkr js_wkr, gplx.core.threads.Gfo_thread_pool thread_pool, Xoa_page page, List_adp imgs, int[] redlink_ary) {
if (imgs.Count() > 0) {
Xof_file_wkr file_thread = new Xof_file_wkr
( wiki.File__orig_mgr(), wiki.File__bin_mgr(), wiki.File__mnt_mgr()
, app.User().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, imgs
);
thread_pool.Add_at_end(file_thread); thread_pool.Run();
}
if (redlink_ary.length > 0) {
Xog_redlink_thread redlink_thread = new Xog_redlink_thread(redlink_ary, js_wkr);
thread_pool.Add_at_end(redlink_thread); thread_pool.Run();
}
}
public void Exec_notify(boolean pass, String msg) {
this.Html_box().Html_js_eval_proc_as_str("xowa.cmds.exec_by_str", "xowa.notify", "{\"text\":\"" + msg + "\",\"status\":\"" + (pass ? "success" : "error") + "\"}");
}
@gplx.Internal protected void Show_url_failed(Load_page_wkr wkr) {
try {
Xog_tab_itm_read_mgr.Show_page_err(win, this, wkr.Wiki(), wkr.Url(), wkr.Ttl(), wkr.Exec_err());
} finally {
wkr.Wiki().Appe().Thread_mgr_old().Page_load_mgr().Resume();
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_show_url_loaded_swt)) this.Show_url_loaded((Load_page_wkr)m.ReadObj("v"));
else if (ctx.Match(k, Invk_show_url_failed_swt)) this.Show_url_failed((Load_page_wkr)m.ReadObj("v"));
else return Gfo_invk_.Rv_unhandled;
return this;
}
public static final String Invk_show_url_loaded_swt = "show_url_loaded_swt", Invk_show_url_failed_swt = "show_url_failed_swt";
}
class Load_files_wkr implements Gfo_thread_wkr {
private Xog_tab_itm tab;
public Load_files_wkr(Xog_tab_itm tab) {this.tab = tab;}
public String Thread__name() {return "xowa.load_files_wkr";}
public boolean Thread__resume() {return true;}
public void Thread__exec() {
try {Xog_async_wkr.Async(tab);}
catch (Exception e) {
tab.Tab_mgr().Win().App().Usr_dlg().Warn_many("error while running file wkr; page=~{0} err=~{1}", tab.Page().Url().To_str(), Err_.Message_gplx_full(e));
}
}
}
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.guis.views;
import gplx.Bry_;
import gplx.Bry_find_;
import gplx.Err_;
import gplx.GfoMsg;
import gplx.Gfo_evt_mgr_;
import gplx.Gfo_invk;
import gplx.Gfo_invk_;
import gplx.Gfo_usr_dlg;
import gplx.GfsCtx;
import gplx.Int_;
import gplx.List_adp;
import gplx.String_;
import gplx.core.envs.Env_;
import gplx.core.threads.Gfo_thread_wkr;
import gplx.gfui.controls.elems.GfuiElem;
import gplx.gfui.controls.elems.GfuiElemKeys;
import gplx.gfui.controls.standards.Gfui_html;
import gplx.gfui.controls.standards.Gfui_tab_itm;
import gplx.gfui.controls.standards.Gfui_tab_itm_data;
import gplx.gfui.ipts.IptBnd_;
import gplx.gfui.ipts.IptCfg_;
import gplx.gfui.ipts.IptEventType_;
import gplx.gfui.ipts.IptKey_;
import gplx.gfui.ipts.IptMouseBtn_;
import gplx.gfui.kits.core.Gfui_kit;
import gplx.xowa.Xoa_app;
import gplx.xowa.Xoa_page;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoa_url_;
import gplx.xowa.Xoae_app;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xow_wiki;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.files.Xof_file_wkr;
import gplx.xowa.files.Xog_redlink_thread;
import gplx.xowa.guis.Xoa_gui_mgr;
import gplx.xowa.guis.bnds.Xog_bnd_box_;
import gplx.xowa.guis.history.Xog_history_mgr;
import gplx.xowa.wikis.pages.Xopg_view_mode_;
import gplx.xowa.wikis.pages.dbs.Xopg_db_page;
public class Xog_tab_itm implements Gfo_invk {
private Xog_win_itm win;
public Xog_tab_itm(Xog_tab_mgr tab_mgr, Gfui_tab_itm_data tab_data, Xowe_wiki wiki, Xoae_page page) {
this.tab_mgr = tab_mgr; this.tab_data = tab_data; this.wiki = wiki; this.page = page;
this.win = tab_mgr.Win();
this.html_itm = new Xog_html_itm(this);
cmd_sync = win.Kit().New_cmd_sync(this);
}
public Xowe_wiki Wiki() {return wiki;} public void Wiki_(Xowe_wiki v) {this.wiki = v;} private Xowe_wiki wiki;
public Gfo_invk Cmd_sync() {return cmd_sync;} private Gfo_invk cmd_sync;
public void Make_html_box(int uid, Gfui_tab_itm tab_box, Xog_win_itm win, GfuiElem owner) {
this.tab_box = tab_box;
Xoae_app app = win.App(); Xoa_gui_mgr gui_mgr = win.Gui_mgr(); Gfui_kit kit = win.Kit();
Gfui_html html_box = kit.New_html("html_box" + Int_.To_str(uid), owner);
html_box.Html_js_enabled_(tab_mgr.Javascript_enabled());
html_box.Html_invk_src_(win);
html_itm.Html_box_(html_box);
if (app.Mode().Tid_is_gui()) { // NOTE: only run for gui; will cause firefox_addon to fail; DATE:2014-05-03
// NOTE: must set source, else control will be empty, and key events will not be raised; DATE:2014-04-30
// NOTE: use load_by_url for nightmode else load_by_mem causes "white flashing" DATE:2017-03-04
if (app.Gui_mgr().Nightmode_mgr().Enabled()) {
html_box.Html_doc_html_load_by_url
( app.Usere().Fsys_mgr().App_temp_html_dir().GenSubFil("tab_new.html")
, String_.new_u8(gplx.xowa.specials.xowa.default_tab.Default_tab_page.DEFAULT_HTML_NIGHT)
);
}
else {
html_box.Html_doc_html_load_by_mem("");
}
IptBnd_.ipt_to_(IptCfg_.Null, html_box, this, "popup", IptEventType_.MouseDown, IptMouseBtn_.Right);
IptBnd_.cmd_to_(IptCfg_.Null, html_box, win, Xog_win_itm.Invk_exit, IptKey_.add_(IptKey_.Alt, IptKey_.F4)); // WORKAROUND:SWT: xulrunner_v24 no longer sends Alt+F4 to SwtShell; must manually subscribe it to quit; DATE:2015-07-31
Gfo_evt_mgr_.Sub_same(html_box, GfuiElemKeys.Evt_menu_detected, html_itm);
gui_mgr.Bnd_mgr().Bind(Xog_bnd_box_.Tid_browser_html, html_box);
if (!Env_.Mode_testing())
kit.Set_mnu_popup(html_box, gui_mgr.Menu_mgr().Popup().Html_page().Under_mnu());
}
}
public void Switch_mem(Xog_tab_itm comp) {
// switch html_itm.owner_tab reference only
html_itm.Switch_mem(comp.html_itm);
// switch .html_itm, since the underlying CTabFolder has reparented the control
Xog_html_itm temp_html_itm = html_itm;
this.html_itm = comp.html_itm;
comp.html_itm = temp_html_itm;
// switch .page, since its underlying html_box has changed and .page must reflect html_box
Xoae_page temp_page = page;
this.page = comp.page;
comp.page = temp_page;
page.Tab_data().Tab_(this); comp.Page().Tab_data().Tab_(comp);
// switch .wiki also; ISSUE#:761; DATE:2020-07-17
Xowe_wiki temp_wiki = wiki;
this.wiki = comp.wiki;
comp.wiki = temp_wiki;
// switch .view_mode to match .page
byte temp_view_mode = view_mode;
this.view_mode = comp.view_mode;
comp.view_mode = temp_view_mode;
// switch .history_mgr along with .page
Xog_history_mgr temp_history_mgr = history_mgr;
this.history_mgr = comp.history_mgr;
comp.history_mgr = temp_history_mgr;
}
public Gfui_tab_itm_data Tab_data() {return tab_data;} private Gfui_tab_itm_data tab_data;
public String Tab_key() {return tab_data.Key();}
public int Tab_idx() {return tab_data.Idx();} public void Tab_idx_(int v) {tab_data.Idx_(v);}
public Xog_tab_mgr Tab_mgr() {return tab_mgr;} private Xog_tab_mgr tab_mgr;
public Gfui_tab_itm Tab_box() {return tab_box;} private Gfui_tab_itm tab_box;
public boolean Tab_is_loading() {return tab_is_loading;} private boolean tab_is_loading;
public Xog_html_itm Html_itm() {return html_itm;} private Xog_html_itm html_itm;
public Gfui_html Html_box() {return html_itm.Html_box();}
public Xoae_page Page() {return page;}
public void Page_ref_(Xoae_page v) {
this.page = v;
this.wiki = page.Wikie(); // NOTE: must update wiki else back doesn't work; DATE:2015-03-05
}
public void Page_(Xoae_page page) {
Page_ref_(page);
this.Page_update_ui(); // force tab button to update when page changes
} private Xoae_page page;
public void Page_update_ui() {
this.Tab_name_();
tab_box.Tab_tip_text_(page.Url().To_str());
}
public void Tab_name_() {
byte[] tab_name = page.Html_data().Custom_tab_name(); // Custom_tab_name set by Special:Default_tab or variants; DATE:2015-10-05
if (tab_name == null) tab_name = page.Ttl().Full_txt(); // no custom_tab_name; use ttl's text
Tab_name_(String_.new_u8(tab_name));
}
public void Tab_name_(String tab_name) {
tab_name = Xog_tab_itm_.Tab_name_min(tab_name, tab_mgr.Btns__min_chars());
tab_name = Xog_tab_itm_.Tab_name_max(tab_name, tab_mgr.Btns__max_chars());
tab_box.Tab_name_(tab_name);
}
public Xog_history_mgr History_mgr() {return history_mgr;} private Xog_history_mgr history_mgr = new Xog_history_mgr();
public byte View_mode() {return view_mode;} private byte view_mode = Xopg_view_mode_.Tid__read;
public void View_mode_(byte v) {
view_mode = v;
if (view_mode != Xopg_view_mode_.Tid__read) // if read, don't bother adding "action=read"
page.Url().Qargs_mgr().Set_val_by_bry(Xoa_url_.Qarg__action, Xopg_view_mode_.To_bry(v));
}
public void Pin_toggle() {}
public void Show_url_bgn(Xoa_url url) {
this.tab_is_loading = true;
Xoae_app app = win.App(); Gfo_usr_dlg usr_dlg = app.Usr_dlg();
// get new_tab_name
this.wiki = (Xowe_wiki)app.Wiki_mgr().Get_by_or_make_init_y(url.Wiki_bry()); // NOTE: must go before wiki.Props().Main_page(); DATE:2016-08-02; NOTE: must load wiki; DATE:2015-07-22
if (url.Page_is_main()) url.Page_bry_(wiki.Props().Main_page()); // NOTE: must go before ttl.Make; DATE:2016-07-31
Xoa_ttl ttl = wiki.Ttl_parse(url.Page_bry());
if (ttl == null) {usr_dlg.Prog_one("", "", "title is invalid: ~{0}", String_.new_u8(url.Raw())); return;}
String new_tab_name = String_.new_u8(ttl.Full_txt());
// if clicking on anchor, just scroll; do not load page
if ( url.Anch_str() != null // url has anchor
&& url.Eq_page(page.Url()) // url has same page_name as existing page
&& url.Qargs_ary().length == 0 // url has no args; needed for Category:A?from=b#mw-pages
&& String_.Eq(new_tab_name, tab_data.Name()) // NOTE: name will be null / empty when starting app and last session had page with #anchor; EX:Main_Page#Links; DATE:2016-07-21
) {
html_itm.Scroll_page_by_id_gui(url.Anch_str());
return;
}
if (win.Page__async__working(url)) return;
if (page != null) page.Tab_data().Close_mgr().When_close(this, url); // cancel any current search cmds
app.Log_wtr().Queue_enabled_(true);
usr_dlg.Gui_wkr().Clear();
if (url.Vnt_bry() != null) {
byte[] vnt = url.Vnt_bry();
if (!Bry_.Eq(vnt, wiki.Lang().Vnt_mgr().Cur_itm().Key()))
wiki.Appe().Cfg().Set_bry_wiki(wiki, Xowe_wiki.Cfg__variant__current, vnt);
}
Tab_name_(new_tab_name);
usr_dlg.Prog_one("", "", "loading: ~{0}", String_.new_u8(ttl.Raw()));
// DELETE: no longer seems needed; popups always disappear when navigating to new page; DATE:2018-11-11
// if (wiki.Html_mgr().Head_mgr().Popup_mgr().Enabled())
// this.Html_box().Html_js_eval_script("if (window.xowa_popups_hide_all != null) window.xowa_popups_hide_all();"); // should be more configurable; DATE:2014-07-09
app.Thread_mgr_old().Page_load_mgr().Add_at_end(new Load_page_wkr(this, wiki, url, ttl)).Run();
}
private void Show_url_loaded(Load_page_wkr wkr) {
Xowe_wiki wiki = wkr.Wiki(); Xoae_page page = wkr.Page();
Xoa_url url = page.Url(); Xoa_ttl ttl = page.Ttl();
Xoae_app app = wiki.Appe(); Gfo_usr_dlg usr_dlg = app.Usr_dlg();
try {
if (page.Tab_data().Cancel_show()) return; // Special:Search canceled show; NOTE: must be inside try b/c finally handles thread
wiki.Parser_mgr().Ctx().Page_(page);
if ( page.Db().Page().Exists_n()
&& !page.Commons_mgr().Xowa_mockup()) { // do not enter "missing" section if File_mockup; EX:en.wikipedia.org/wiki/File:Protoplanetary-disk.jpg DATE:2016-11-13
if (wiki.Db_mgr().Save_mgr().Create_enabled()
|| wiki.Page_mgr().Sync_mgr().Auto_enabled()) {
page = Xoae_page.New_edit(wiki, ttl);
page.Url_(url); // NOTE: need to set url else query args like action=edit will be lost; DATE:2019-03-20
view_mode = Xopg_view_mode_.Tid__edit;
history_mgr.Add(page); // NOTE: must put new_page on stack so that pressing back will pop new_page, not previous page
Xog_tab_itm_read_mgr.Show_page(this, page, false);
}
else {
wkr.Page().Tab_data().Tab().Page_(page); // NOTE: must set tab's page to current page, so that switching to it will update url bar; EX:pt.b:A"MANUAL_DE_PROCEDURI_.Sectiunea:""CONTABILITATE_SI_MANAGEMENT_FINANCIAR""" DATE:2015-09-17
if (page.Redirect_trail().Itms__len() > 0)
usr_dlg.Prog_many("", "", "could not find page in wiki: ~{0} (redirected from ~{1})", String_.new_u8(page.Url().Page_bry()), page.Redirect_trail().Itms__get_at_0th_or_null());
else {
if (ttl.Ns().Id_is_file())
usr_dlg.Prog_one("", "", "commons.wikimedia.org must be installed in order to view the file. See [[App/Wiki_types/Commons]]: ~{0}", String_.new_u8(url.Raw()));// HOME
else
usr_dlg.Prog_one("", "", "could not find page in wiki: ~{0}", String_.new_u8(url.Raw()));
}
}
app.Log_wtr().Queue_enabled_(false);
return;
}
// if (!page.Redirected()) page.Url_(url); // NOTE: handle redirect from commons; COMMENTED: part of redirect rewrite; DATE:2016-07-05
if (page.Ttl().Anch_bgn() != Bry_find_.Not_found) page.Url().Anch_bry_(page.Ttl().Anch_txt()); // NOTE: occurs when page is a redirect to an anchor; EX: w:Duck race -> Rubber duck#Races
history_mgr.Add(page);
Xog_tab_itm_read_mgr.Show_page(this, page, true);
if (app.Usere().History_mgr().Enabled()) {
app.Usere().History_mgr().Add(page);
app.User().User_db_mgr().History_mgr().Update_async(app.Async_mgr(), ttl, url);
}
usr_dlg.Prog_none("", "", "rendering html");
// html_itm.Html_box().Size_(tab_mgr.Tab_mgr().Size()); // COMMENTED: causes clicks on macosx to be off by 4 px; NOTE: must resize tab here, else scrolling to anchor in background tab doesn't work (html_box has size of 0, 0) DATE:2015-05-03
// win.Page__async__bgn(this);
Gfo_thread_wkr async_wkr = null;
if (page.Html_data().Hdump_exists()) {
// wiki.File_mgr().Init_file_mgr_by_load(wiki);
// Xof_fsdb_mgr fsdb_mgr = wiki.File_mgr().Fsdb_mgr();
// async_wkr = new Xof_file_wkr(wiki.File__orig_mgr(), fsdb_mgr.Bin_mgr(), fsdb_mgr.Mnt_mgr(), app.Usere().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, page.Hdump_mgr().Imgs());
async_wkr = new Load_files_wkr(this);
if (wiki.Html__hdump_enabled() && page.Db().Page().Html_db_id() == Xopg_db_page.HTML_DB_ID_NULL) {
wiki.Html__hdump_mgr().Save_mgr().Save(page);
}
}
else
async_wkr = new Load_files_wkr(this);
page.Html_data().Mode_wtxt_shown_y_();
app.Thread_mgr_old().File_load_mgr().Add_at_end(async_wkr).Run();
// app.Thread_mgr().Get_by_or_new("on_page_load").Add(new Xopg_img_thread(), new Xopg_rl_thread());
}
finally {
app.Thread_mgr_old().Page_load_mgr().Resume();
this.tab_is_loading = false;
}
}
public void Exec_async_hdump(Xoa_app app, Xow_wiki wiki, gplx.xowa.guis.cbks.js.Xog_js_wkr js_wkr, gplx.core.threads.Gfo_thread_pool thread_pool, Xoa_page page, List_adp imgs, int[] redlink_ary) {
if (imgs.Count() > 0) {
Xof_file_wkr file_thread = new Xof_file_wkr
( wiki.File__orig_mgr(), wiki.File__bin_mgr(), wiki.File__mnt_mgr()
, app.User().User_db_mgr().Cache_mgr(), wiki.File__repo_mgr(), html_itm, page, imgs
);
thread_pool.Add_at_end(file_thread); thread_pool.Run();
}
if (redlink_ary.length > 0) {
Xog_redlink_thread redlink_thread = new Xog_redlink_thread(redlink_ary, js_wkr);
thread_pool.Add_at_end(redlink_thread); thread_pool.Run();
}
}
public void Exec_notify(boolean pass, String msg) {
this.Html_box().Html_js_eval_proc_as_str("xowa.cmds.exec_by_str", "xowa.notify", "{\"text\":\"" + msg + "\",\"status\":\"" + (pass ? "success" : "error") + "\"}");
}
@gplx.Internal protected void Show_url_failed(Load_page_wkr wkr) {
try {
Xog_tab_itm_read_mgr.Show_page_err(win, this, wkr.Wiki(), wkr.Url(), wkr.Ttl(), wkr.Exec_err());
} finally {
wkr.Wiki().Appe().Thread_mgr_old().Page_load_mgr().Resume();
}
}
public Object Invk(GfsCtx ctx, int ikey, String k, GfoMsg m) {
if (ctx.Match(k, Invk_show_url_loaded_swt)) this.Show_url_loaded((Load_page_wkr)m.ReadObj("v"));
else if (ctx.Match(k, Invk_show_url_failed_swt)) this.Show_url_failed((Load_page_wkr)m.ReadObj("v"));
else return Gfo_invk_.Rv_unhandled;
return this;
}
public static final String Invk_show_url_loaded_swt = "show_url_loaded_swt", Invk_show_url_failed_swt = "show_url_failed_swt";
}
class Load_files_wkr implements Gfo_thread_wkr {
private Xog_tab_itm tab;
public Load_files_wkr(Xog_tab_itm tab) {this.tab = tab;}
public String Thread__name() {return "xowa.load_files_wkr";}
public boolean Thread__resume() {return true;}
public void Thread__exec() {
try {Xog_async_wkr.Async(tab);}
catch (Exception e) {
tab.Tab_mgr().Win().App().Usr_dlg().Warn_many("error while running file wkr; page=~{0} err=~{1}", tab.Page().Url().To_str(), Err_.Message_gplx_full(e));
}
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,148 +13,171 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.guis.views; import gplx.*; import gplx.xowa.*; import gplx.xowa.guis.*;
import gplx.gfui.*; import gplx.gfui.controls.standards.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.wikis.pages.*;
import gplx.xowa.wikis.nss.*;
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
public class Xog_tab_itm_edit_mgr {
public static void Save(Xog_tab_itm tab, boolean quick_save) {
if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+s being pressed in read/html modes
// get text and save directly to text_db
Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win();
byte[] new_text = Get_new_text(tab, page.Db().Text().Text_bry());
int page_id = page.Db().Page().Id();
if (page.Edit_mode() == Xoa_page_.Edit_mode_create) {
page_id = wiki.Db_mgr().Save_mgr().Data_create(wiki, page.Ttl(), new_text);
page.Db().Page().Id_(page_id);
page.Edit_mode_update_(); // set to update so that next save does not try to create
}
else {
wiki.Db_mgr().Save_mgr().Data_update(page, new_text);
}
Invalidate(wiki);
page.Db().Text().Text_bry_(new_text);
// refresh html
wiki.Parser_mgr().Parse(page, true);
if (wiki.Html__hdump_enabled()) wiki.Html__hdump_mgr().Save_mgr().Save(page); // must go after wiki.Parse
// NOTE: show message after Parse, b/c Parse will flash "Loading page"; DATE:2014-05-17
win_itm.Usr_dlg().Prog_many("", "", "saved ~{0} (~{1})"
, String_.new_u8(page.Ttl().Full_txt_raw())
, Datetime_now.Get().XtoStr_fmt("HH:mm:ss.fff")
);
// full_save; save page and go to read mode
if (!quick_save) {
gplx.xowa.addons.wikis.pagebaks.Pagebaks_addon.On_page_saved(wiki.Appe(), wiki, page.Ttl(), new_text);
// update categories
try {
wiki.Html_mgr().Page_wtr_mgr().Gen(page, Xopg_view_mode_.Tid__read); // NOTE: need to write html to fill Wtxt().Ctgs
gplx.xowa.addons.wikis.ctgs.edits.Xoctg_edit_mgr.Update(wiki, page.Ttl().Page_db(), page_id, page.Wtxt().Ctgs__to_ary());
} catch (Exception e) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to update categories; err=~{0}", Err_.Message_gplx_log(e));
}
// TODO: save html copy
//wiki.Db_mgr().Hdump_mgr().Save(page);
// parse page and show it
page.Html_data().Edit_preview_(Bry_.Empty);
Xoae_page stack_page = tab.History_mgr().Cur_page(wiki); // NOTE: must be to CurPage() else changes will be lost when going Bwd,Fwd
stack_page.Db().Text().Text_bry_(page.Db().Text().Text_bry()); // NOTE: overwrite with "saved" changes
stack_page.Wikie().Parser_mgr().Parse(page, true); // NOTE: must reparse page if (a) Edit -> Read; or (b) "Options" save
page.Url_(Xoa_url.New(tab.Wiki().Domain_bry(), tab.Page().Ttl().Full_db()));
// force full reload of page; needed to refresh page_modified; DATE:2017-03-06
tab.Show_url_bgn(page.Url());
// win_itm.Page__mode_(Xopg_view_mode_.Tid__read);
// win_itm.Page__async__bgn(tab);
}
}
public static void Preview(Xog_tab_itm tab) {
if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles preview somehow being called?
Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win();
Xog_html_itm html_itm = tab.Html_itm();
byte[] new_text = Get_new_text(tab, null);
Xoae_page new_page = Xoae_page.New(wiki, page.Ttl());
new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-11-25
new_page.Db().Page().Id_(page.Db().Page().Id()); // NOTE: page_id needed for sqlite (was not needed for xdat)
new_page.Db().Text().Text_bry_(new_text);
wiki.Parser_mgr().Parse(new_page, true); // refresh html
tab.Page_(new_page); new_page.Tab_data().Tab_(tab); // replace old page with new_page; DATE:2014-10-09
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
Xoh_page_wtr_wkr wkr = wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read);
wkr.Write_body(tmp_bfr, wiki.Parser_mgr().Ctx(), Xoh_wtr_ctx.Basic, new_page);
byte[] new_html = tmp_bfr.To_bry_and_rls();
new_page.Html_data().Edit_preview_(new_html);
Invalidate(wiki);
win_itm.Page__mode_(Xopg_view_mode_.Tid__edit);
html_itm.Scroll_page_by_id_gui(Xog_html_itm.Elem_id__first_heading);// NOTE: was originally directly; changed to call on thread; DATE:2014-05-03
win_itm.Page__async__bgn(tab); // NOTE: needed to show images during preview; DATE:2014-06-21
}
public static void Rename(Xog_tab_itm tab) {
if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+r being pressed
Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win();
if (Bry_.Eq(page.Ttl().Page_db(), wiki.Props().Main_page())) {
win_itm.Usr_dlg().Warn_many("", "", "The Main Page cannot be renamed");
win_itm.Kit().Ask_ok("", "", "The Main Page cannot be renamed");
return;
}
byte[] new_text = Bry_.new_u8(tab.Html_itm().Get_elem_value(Xog_html_itm.Elem_id__xowa_edit_rename_box));
if (Bry_.Len_eq_0(new_text)) return; // no ttl given; exit
new_text = Xoa_ttl.Replace_spaces(new_text); // ttls cannot have spaces; only underscores
Xoa_ttl new_ttl = Xoa_ttl.Parse(wiki, new_text);
int new_ns_id = new_ttl.Ns().Id();
if (new_ns_id != Xow_ns_.Tid__main) {
win_itm.Usr_dlg().Warn_many("", "", "The new page name must remain in the same namespace");
return;
}
wiki.Db_mgr().Save_mgr().Data_rename(page, new_ns_id, new_text);
page.Ttl_(Xoa_ttl.Parse(wiki, Bry_.Add(page.Ttl().Ns().Name_db_w_colon(), new_text)));
win_itm.Page__mode_(Xopg_view_mode_.Tid__read);
win_itm.Usr_dlg().Prog_one("", "", "renamed page to {0}", String_.new_u8(page.Ttl().Full_txt_raw()));
}
public static void Focus(Xog_win_itm win, String elem_focus_id) {
Gfui_html html_box = win.Active_html_box();
html_box.Focus();
html_box.Html_js_eval_proc_as_str(Xog_js_procs.Doc__elem_focus, elem_focus_id);
}
public static void Debug(Xog_win_itm win, byte view_tid) {
Xog_tab_itm tab = win.Tab_mgr().Active_tab(); Xoae_page page = tab.Page();
Xowe_wiki wiki = tab.Wiki(); Xop_ctx ctx = wiki.Parser_mgr().Ctx();
ctx.Defn_trace().Clear(); // TODO_OLD: move_me
ctx.Defn_trace_(Xot_defn_trace_dbg.Instance);
Xoa_ttl ttl = page.Ttl();
Xoae_page new_page = Xoae_page.New(wiki, ttl);
new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-12-09
byte[] data = tab.Html_itm().Get_elem_value_for_edit_box_as_bry();
new_page.Db().Text().Text_bry_(data);
wiki.Parser_mgr().Parse(new_page, true);
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_m001();
bfr.Add(new_page.Root().Root_src());
wiki.Parser_mgr().Ctx().Defn_trace().Print(data, bfr);
new_page.Db().Text().Text_bry_(bfr.To_bry_and_rls());
byte old = tab.View_mode();
tab.View_mode_(view_tid);
Xog_tab_itm_read_mgr.Show_page(tab, new_page, false);
tab.History_mgr().Add(new_page);
tab.View_mode_(old);
}
private static void Invalidate(Xowe_wiki wiki) {// invalidate everything on updates; especially needed for page transclusion; {{/my_subpage}} DATE:2014-04-10
wiki.Parser_mgr().Scrib().Core_term();
wiki.Cache_mgr().Free_mem__all();
}
private static byte[] Get_new_text(Xog_tab_itm tab, byte[] orig) {
byte[] rv = tab.Html_itm().Get_elem_value_for_edit_box_as_bry();
if (orig != null) // orig == null for Preview
rv = tab.Wiki().Parser_mgr().Hdr__section_editable__mgr().Merge_section(tab.Page().Url(), rv, orig);
rv = Bry_.Trim(rv, 0, rv.length, false, true, Bry_.Trim_ary_ws, true); // MW: trim all trailing ws; REF:EditPage.php!safeUnicodeInput; DATE:2014-04-25
return rv;
}
}
package gplx.xowa.guis.views;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Datetime_now;
import gplx.Err_;
import gplx.Gfo_usr_dlg_;
import gplx.String_;
import gplx.gfui.controls.standards.Gfui_html;
import gplx.xowa.Xoa_page_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.htmls.Xoh_page_wtr_wkr;
import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx;
import gplx.xowa.parsers.Xop_ctx;
import gplx.xowa.parsers.tmpls.Xot_defn_trace_dbg;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
import gplx.xowa.wikis.nss.Xow_ns_;
import gplx.xowa.wikis.pages.Xopg_view_mode_;
public class Xog_tab_itm_edit_mgr {
public static void Save(Xog_tab_itm tab, boolean quick_save) {
if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+s being pressed in read/html modes
// get text and save directly to text_db
Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win();
byte[] new_text = Get_new_text(tab, page.Db().Text().Text_bry());
int page_id = page.Db().Page().Id();
if (page.Edit_mode() == Xoa_page_.Edit_mode_create) {
page_id = wiki.Db_mgr().Save_mgr().Data_create(wiki, page.Ttl(), new_text);
page.Db().Page().Id_(page_id);
page.Edit_mode_update_(); // set to update so that next save does not try to create
}
else {
wiki.Db_mgr().Save_mgr().Data_update(page, new_text);
}
Invalidate(wiki);
page.Db().Text().Text_bry_(new_text);
// refresh html
wiki.Parser_mgr().Parse(page, true);
if (wiki.Html__hdump_enabled()) wiki.Html__hdump_mgr().Save_mgr().Save(page); // must go after wiki.Parse
// NOTE: show message after Parse, b/c Parse will flash "Loading page"; DATE:2014-05-17
win_itm.Usr_dlg().Prog_many("", "", "saved ~{0} (~{1})"
, String_.new_u8(page.Ttl().Full_txt_raw())
, Datetime_now.Get().XtoStr_fmt("HH:mm:ss.fff")
);
// full_save; save page and go to read mode
if (!quick_save) {
gplx.xowa.addons.wikis.pagebaks.Pagebaks_addon.On_page_saved(wiki.Appe(), wiki, page.Ttl(), new_text);
// update categories
try {
wiki.Html_mgr().Page_wtr_mgr().Gen(page, Xopg_view_mode_.Tid__read); // NOTE: need to write html to fill Wtxt().Ctgs
gplx.xowa.addons.wikis.ctgs.edits.Xoctg_edit_mgr.Update(wiki, page.Ttl().Page_db(), page_id, page.Wtxt().Ctgs__to_ary());
} catch (Exception e) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to update categories; err=~{0}", Err_.Message_gplx_log(e));
}
// reload html_db_id b/c it gets cleared in Xopg_db_page; ISSUE#:699; DATE:2020-08-06
Xowd_page_itm rv = new Xowd_page_itm();
wiki.Data__core_mgr().Tbl__page().Select_by_ttl(rv, page.Ttl().Ns(), page.Ttl().Page_db());
page.Db().Page().Html_db_id_(rv.Html_db_id());
// save html
wiki.Html__hdump_mgr().Save_mgr().Save(page, true);
// parse page and show it
page.Html_data().Edit_preview_(Bry_.Empty);
Xoae_page stack_page = tab.History_mgr().Cur_page(wiki); // NOTE: must be to CurPage() else changes will be lost when going Bwd,Fwd
stack_page.Db().Text().Text_bry_(page.Db().Text().Text_bry()); // NOTE: overwrite with "saved" changes
stack_page.Wikie().Parser_mgr().Parse(page, true); // NOTE: must reparse page if (a) Edit -> Read; or (b) "Options" save
page.Url_(Xoa_url.New(tab.Wiki().Domain_bry(), tab.Page().Ttl().Full_db()));
// force full reload of page; needed to refresh page_modified; DATE:2017-03-06
tab.Show_url_bgn(page.Url());
// win_itm.Page__mode_(Xopg_view_mode_.Tid__read);
// win_itm.Page__async__bgn(tab);
}
}
public static void Preview(Xog_tab_itm tab) {
if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles preview somehow being called?
Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win();
Xog_html_itm html_itm = tab.Html_itm();
byte[] new_text = Get_new_text(tab, null);
Xoae_page new_page = Xoae_page.New(wiki, page.Ttl());
new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-11-25
new_page.Db().Page().Id_(page.Db().Page().Id()); // NOTE: page_id needed for sqlite (was not needed for xdat)
new_page.Db().Text().Text_bry_(new_text);
wiki.Parser_mgr().Parse(new_page, true); // refresh html
tab.Page_(new_page); new_page.Tab_data().Tab_(tab); // replace old page with new_page; DATE:2014-10-09
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
Xoh_page_wtr_wkr wkr = wiki.Html_mgr().Page_wtr_mgr().Wkr(Xopg_view_mode_.Tid__read);
wkr.Write_body(tmp_bfr, wiki.Parser_mgr().Ctx(), Xoh_wtr_ctx.Basic, new_page);
byte[] new_html = tmp_bfr.To_bry_and_rls();
new_page.Html_data().Edit_preview_(new_html);
Invalidate(wiki);
win_itm.Page__mode_(Xopg_view_mode_.Tid__edit);
html_itm.Scroll_page_by_id_gui(Xog_html_itm.Elem_id__first_heading);// NOTE: was originally directly; changed to call on thread; DATE:2014-05-03
win_itm.Page__async__bgn(tab); // NOTE: needed to show images during preview; DATE:2014-06-21
}
public static void Rename(Xog_tab_itm tab) {
if (tab.View_mode() != Xopg_view_mode_.Tid__edit) return; // exit if not edit; handles ctrl+r being pressed
Xoae_page page = tab.Page(); Xowe_wiki wiki = tab.Wiki(); Xog_win_itm win_itm = tab.Tab_mgr().Win();
if (Bry_.Eq(page.Ttl().Page_db(), wiki.Props().Main_page())) {
win_itm.Usr_dlg().Warn_many("", "", "The Main Page cannot be renamed");
win_itm.Kit().Ask_ok("", "", "The Main Page cannot be renamed");
return;
}
byte[] new_text = Bry_.new_u8(tab.Html_itm().Get_elem_value(Xog_html_itm.Elem_id__xowa_edit_rename_box));
if (Bry_.Len_eq_0(new_text)) return; // no ttl given; exit
new_text = Xoa_ttl.Replace_spaces(new_text); // ttls cannot have spaces; only underscores
Xoa_ttl new_ttl = Xoa_ttl.Parse(wiki, new_text);
int new_ns_id = new_ttl.Ns().Id();
if (new_ns_id != Xow_ns_.Tid__main) {
win_itm.Usr_dlg().Warn_many("", "", "The new page name must remain in the same namespace");
return;
}
wiki.Db_mgr().Save_mgr().Data_rename(page, new_ns_id, new_text);
page.Ttl_(Xoa_ttl.Parse(wiki, Bry_.Add(page.Ttl().Ns().Name_db_w_colon(), new_text)));
win_itm.Page__mode_(Xopg_view_mode_.Tid__read);
win_itm.Usr_dlg().Prog_one("", "", "renamed page to {0}", String_.new_u8(page.Ttl().Full_txt_raw()));
}
public static void Focus(Xog_win_itm win, String elem_focus_id) {
Gfui_html html_box = win.Active_html_box();
html_box.Focus();
html_box.Html_js_eval_proc_as_str(Xog_js_procs.Doc__elem_focus, elem_focus_id);
}
public static void Debug(Xog_win_itm win, byte view_tid) {
Xog_tab_itm tab = win.Tab_mgr().Active_tab(); Xoae_page page = tab.Page();
Xowe_wiki wiki = tab.Wiki(); Xop_ctx ctx = wiki.Parser_mgr().Ctx();
ctx.Defn_trace().Clear(); // TODO_OLD: move_me
ctx.Defn_trace_(Xot_defn_trace_dbg.Instance);
Xoa_ttl ttl = page.Ttl();
Xoae_page new_page = Xoae_page.New(wiki, ttl);
new_page.Url_(page.Url()); // NOTE: must set Url explicitly, else new_page will not have same url_args as old_page; broken when going to action=edit; DATE:2018-12-09
byte[] data = tab.Html_itm().Get_elem_value_for_edit_box_as_bry();
new_page.Db().Text().Text_bry_(data);
wiki.Parser_mgr().Parse(new_page, true);
Bry_bfr bfr = wiki.Utl__bfr_mkr().Get_m001();
bfr.Add(new_page.Root().Root_src());
wiki.Parser_mgr().Ctx().Defn_trace().Print(data, bfr);
new_page.Db().Text().Text_bry_(bfr.To_bry_and_rls());
byte old = tab.View_mode();
tab.View_mode_(view_tid);
Xog_tab_itm_read_mgr.Show_page(tab, new_page, false);
tab.History_mgr().Add(new_page);
tab.View_mode_(old);
}
private static void Invalidate(Xowe_wiki wiki) {// invalidate everything on updates; especially needed for page transclusion; {{/my_subpage}} DATE:2014-04-10
wiki.Parser_mgr().Scrib().Core_term();
wiki.Cache_mgr().Free_mem__all();
}
private static byte[] Get_new_text(Xog_tab_itm tab, byte[] orig) {
byte[] rv = tab.Html_itm().Get_elem_value_for_edit_box_as_bry();
if (orig != null) // orig == null for Preview
rv = tab.Wiki().Parser_mgr().Hdr__section_editable__mgr().Merge_section(tab.Page().Url(), rv, orig);
rv = Bry_.Trim(rv, 0, rv.length, false, true, Bry_.Trim_ary_ws, true); // MW: trim all trailing ws; REF:EditPage.php!safeUnicodeInput; DATE:2014-04-25
return rv;
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,74 +13,106 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.htmls.core; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*;
import gplx.xowa.htmls.core.htmls.*; import gplx.xowa.htmls.core.wkrs.*; import gplx.xowa.htmls.core.hzips.*; import gplx.xowa.htmls.heads.*; import gplx.xowa.htmls.core.dbs.*;
import gplx.core.ios.*; import gplx.core.primitives.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.pages.*;
import gplx.xowa.addons.wikis.pages.syncs.core.parsers.*;
public class Xow_hdump_mgr__save {
private final Xow_wiki wiki; private final Xoh_hzip_mgr hzip_mgr; private final Io_stream_zip_mgr zip_mgr;
private final Xoh_page tmp_hpg; private final Xoh_hzip_bfr tmp_bfr = Xoh_hzip_bfr.New_txt(32); private Bool_obj_ref html_db_is_new = Bool_obj_ref.n_();
private int dflt_zip_tid, dflt_hzip_tid;
public Xow_hdump_mgr__save(Xow_wiki wiki, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, Xoh_page tmp_hpg) {
this.wiki = wiki; this.hzip_mgr = hzip_mgr; this.zip_mgr = zip_mgr; this.tmp_hpg = tmp_hpg;
}
public void Init_by_db(int dflt_zip_tid, int dflt_hzip_tid, boolean mode_is_b256) {
this.dflt_zip_tid = dflt_zip_tid; this.dflt_hzip_tid = dflt_hzip_tid; tmp_bfr.Mode_is_b256_(mode_is_b256);
}
public byte[] Src_as_hzip() {return src_as_hzip;} private byte[] src_as_hzip;
public int Save(Xoae_page page) {
synchronized (tmp_hpg) {
Bld_hdump(page);
tmp_hpg.Ctor_by_hdiff(tmp_bfr, page, page.Wikie().Msg_mgr().Val_by_id(gplx.xowa.langs.msgs.Xol_msg_itm_.Id_toc));
Xow_db_file html_db = Get_html_db(wiki, page, html_db_is_new.Val_n_());
return Save(page, tmp_hpg, html_db.Tbl__html(), html_db_is_new.Val(), true);
}
}
public int Save(Xoae_page page, Xoh_page hpg, Xowd_html_tbl html_tbl, boolean insert, boolean use_hzip_dflt) {
int hzip_tid = use_hzip_dflt ? dflt_hzip_tid : Xoh_hzip_dict_.Hdb__htxt;
byte[] db_body = Write(tmp_bfr, wiki, page, hpg, hzip_mgr, zip_mgr, dflt_zip_tid, hzip_tid, hpg.Db().Html().Html_bry());
if (insert) html_tbl.Insert(hpg, dflt_zip_tid, dflt_hzip_tid, db_body);
else html_tbl.Update(hpg, dflt_zip_tid, dflt_hzip_tid, db_body);
return db_body.length;
}
public void Bld_hdump(Xoae_page page) {
page.File_queue().Clear(); // need to reset uid to 0, else xowa_file_# will keep incrementing upwards
Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Hdump_by_hzip_tid(dflt_hzip_tid);
wiki.Html__wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Write_body(tmp_bfr, page.Wikie().Parser_mgr().Ctx(), hctx, page); // save as hdump_fmt
page.Db().Html().Html_bry_(tmp_bfr.To_bry_and_clear());
}
private byte[] Write(Xoh_hzip_bfr bfr, Xow_wiki wiki, Xoae_page page, Xoh_page hpg, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, int zip_tid, int hzip_tid, byte[] src) {
switch (hzip_tid) {
case Xoh_hzip_dict_.Hdb__htxt:
break;
case Xoh_hzip_dict_.Hdb__hzip:
src = hzip_mgr.Encode_as_bry((Xoh_hzip_bfr)bfr.Clear(), wiki, hpg, src);
break;
// TOMBSTONE: not used; Xosync_update_mgr calls save directly; unsure if this should be restored for parallelism
// case Xoh_hzip_dict_.Hdb__page_sync:
// src = plain_parser.Parse_hdoc(wiki.Domain_itm(), page.Url_bry_safe(), hpg.Hdump_mgr().Imgs(), src);
// break;
}
src_as_hzip = src;
if (zip_tid > gplx.core.ios.streams.Io_stream_tid_.Tid__raw)
src = zip_mgr.Zip((byte)zip_tid, src);
return src;
}
private static Xow_db_file Get_html_db(Xow_wiki wiki, Xoae_page page, Bool_obj_ref html_db_is_new) {
Xow_db_file rv = Xow_db_file.Null;
Xow_db_mgr core_data_mgr = wiki.Data__core_mgr();
int html_db_id = page.Db().Page().Html_db_id();
if (html_db_id == -1) {
html_db_is_new.Val_y_();
rv = core_data_mgr.Db__html();
if (rv == null) rv = core_data_mgr.Dbs__make_by_tid(Xow_db_file_.Tid__html_data);
html_db_id = rv.Id();
page.Db().Page().Html_db_id_(html_db_id);
core_data_mgr.Tbl__page().Update__html_db_id(page.Db().Page().Id(), html_db_id);
}
else {
rv = core_data_mgr.Dbs__get_by_id_or_fail(html_db_id);
}
return rv;
}
}
package gplx.xowa.htmls.core;
import gplx.core.ios.Io_stream_zip_mgr;
import gplx.core.primitives.Bool_obj_ref;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xow_wiki;
import gplx.xowa.htmls.Xoh_page;
import gplx.xowa.htmls.core.dbs.Xowd_html_tbl;
import gplx.xowa.htmls.core.htmls.Xoh_wtr_ctx;
import gplx.xowa.htmls.core.hzips.Xoh_hzip_dict_;
import gplx.xowa.htmls.core.hzips.Xoh_hzip_mgr;
import gplx.xowa.htmls.core.wkrs.Xoh_hzip_bfr;
import gplx.xowa.wikis.data.Xow_db_file;
import gplx.xowa.wikis.data.Xow_db_file_;
import gplx.xowa.wikis.data.Xow_db_mgr;
import gplx.xowa.wikis.pages.Xopg_view_mode_;
import gplx.xowa.wikis.pages.dbs.Xopg_db_page;
public class Xow_hdump_mgr__save {
private final Xow_wiki wiki; private final Xoh_hzip_mgr hzip_mgr; private final Io_stream_zip_mgr zip_mgr;
private final Xoh_page tmp_hpg; private final Xoh_hzip_bfr tmp_bfr = Xoh_hzip_bfr.New_txt(32); private Bool_obj_ref html_db_is_new = Bool_obj_ref.n_();
private int dflt_zip_tid, dflt_hzip_tid;
public Xow_hdump_mgr__save(Xow_wiki wiki, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, Xoh_page tmp_hpg) {
this.wiki = wiki; this.hzip_mgr = hzip_mgr; this.zip_mgr = zip_mgr; this.tmp_hpg = tmp_hpg;
}
public void Init_by_db(int dflt_zip_tid, int dflt_hzip_tid, boolean mode_is_b256) {
this.dflt_zip_tid = dflt_zip_tid; this.dflt_hzip_tid = dflt_hzip_tid; tmp_bfr.Mode_is_b256_(mode_is_b256);
}
public byte[] Src_as_hzip() {return src_as_hzip;} private byte[] src_as_hzip;
public int Save(Xoae_page page) {return Save(page, false);}
public int Save(Xoae_page page, boolean isEdit) {
synchronized (tmp_hpg) {
Bld_hdump(page);
tmp_hpg.Ctor_by_hdiff(tmp_bfr, page, page.Wikie().Msg_mgr().Val_by_id(gplx.xowa.langs.msgs.Xol_msg_itm_.Id_toc));
Xow_db_file html_db = Get_html_db(wiki, page, html_db_is_new.Val_n_(), isEdit);
return Save(page, tmp_hpg, html_db.Tbl__html(), html_db_is_new.Val(), true);
}
}
public int Save(Xoae_page page, Xoh_page hpg, Xowd_html_tbl html_tbl, boolean insert, boolean use_hzip_dflt) {
int hzip_tid = use_hzip_dflt ? dflt_hzip_tid : Xoh_hzip_dict_.Hdb__htxt;
byte[] db_body = Write(tmp_bfr, wiki, page, hpg, hzip_mgr, zip_mgr, dflt_zip_tid, hzip_tid, hpg.Db().Html().Html_bry());
if (insert) html_tbl.Insert(hpg, dflt_zip_tid, dflt_hzip_tid, db_body);
else html_tbl.Update(hpg, dflt_zip_tid, dflt_hzip_tid, db_body);
return db_body.length;
}
public void Bld_hdump(Xoae_page page) {
page.File_queue().Clear(); // need to reset uid to 0, else xowa_file_# will keep incrementing upwards
Xoh_wtr_ctx hctx = Xoh_wtr_ctx.Hdump_by_hzip_tid(dflt_hzip_tid);
wiki.Html__wtr_mgr().Wkr(Xopg_view_mode_.Tid__read).Write_body(tmp_bfr, page.Wikie().Parser_mgr().Ctx(), hctx, page); // save as hdump_fmt
page.Db().Html().Html_bry_(tmp_bfr.To_bry_and_clear());
}
private byte[] Write(Xoh_hzip_bfr bfr, Xow_wiki wiki, Xoae_page page, Xoh_page hpg, Xoh_hzip_mgr hzip_mgr, Io_stream_zip_mgr zip_mgr, int zip_tid, int hzip_tid, byte[] src) {
switch (hzip_tid) {
case Xoh_hzip_dict_.Hdb__htxt:
break;
case Xoh_hzip_dict_.Hdb__hzip:
src = hzip_mgr.Encode_as_bry((Xoh_hzip_bfr)bfr.Clear(), wiki, hpg, src);
break;
// TOMBSTONE: not used; Xosync_update_mgr calls save directly; unsure if this should be restored for parallelism
// case Xoh_hzip_dict_.Hdb__page_sync:
// src = plain_parser.Parse_hdoc(wiki.Domain_itm(), page.Url_bry_safe(), hpg.Hdump_mgr().Imgs(), src);
// break;
}
src_as_hzip = src;
if (zip_tid > gplx.core.ios.streams.Io_stream_tid_.Tid__raw)
src = zip_mgr.Zip((byte)zip_tid, src);
return src;
}
private static Xow_db_file Get_html_db(Xow_wiki wiki, Xoae_page page, Bool_obj_ref html_db_is_new, boolean isEdit) {
Xow_db_file rv = Xow_db_file.Null;
Xow_db_mgr core_data_mgr = wiki.Data__core_mgr();
int html_db_id = page.Db().Page().Html_db_id();
if (html_db_id == Xopg_db_page.HTML_DB_ID_NULL) {
html_db_is_new.Val_y_();
// get htmlDbTid; NOTE: probably do not need Tid__html_data b/c xomp_wkr and sync_mgr should be building the databases; ISSUE#:699; DATE:2020-08-06
byte htmlDbTid = isEdit ? Xow_db_file_.Tid__html_user : Xow_db_file_.Tid__html_data;
// get htmlDb
if (isEdit) {
rv = core_data_mgr.Dbs__get_by_tid_or_null(htmlDbTid);
}
else {
rv = core_data_mgr.Db__html();
}
// make htmlDb if not available
if (rv == null) {
rv = core_data_mgr.Dbs__make_by_tid(htmlDbTid);
Xowd_html_tbl html_tbl = new Xowd_html_tbl(rv.Conn());
html_tbl.Create_tbl();
}
html_db_id = rv.Id();
page.Db().Page().Html_db_id_(html_db_id);
core_data_mgr.Tbl__page().Update__html_db_id(page.Db().Page().Id(), html_db_id);
}
else {
rv = core_data_mgr.Dbs__get_by_id_or_fail(html_db_id);
}
return rv;
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,85 +13,111 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.htmls.hxtns.blobs; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.hxtns.*;
import gplx.dbs.*;
import gplx.core.ios.*;
public class Hxtn_blob_tbl implements Rls_able {
private static final String tbl_name = "hxtn_blob"; private static final Dbmeta_fld_list flds = new Dbmeta_fld_list();
private static final String
fld_blob_tid = flds.Add_int("blob_tid"), fld_wiki_id = flds.Add_int("wiki_id"), fld_blob_id = flds.Add_int("blob_id")
, fld_zip_tid = flds.Add_byte("zip_tid"), fld_blob_data = flds.Add_bry("blob_data");
private final Db_conn conn; private Db_stmt stmt_insert;
private final byte zip_tid_default;
private final Io_stream_zip_mgr zip_mgr = new Io_stream_zip_mgr();
public Hxtn_blob_tbl(Db_conn conn, byte zip_tid_default) {
this.conn = conn;
conn.Rls_reg(this);
this.zip_tid_default = zip_tid_default;
}
public String Tbl_name() {return tbl_name;}
public Db_conn Conn() {return conn;}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Rls() {
stmt_insert = Db_stmt_.Rls(stmt_insert);
}
public void Stmt_bgn() {
stmt_insert = conn.Stmt_insert(tbl_name, flds);
}
public void Stmt_end() {
this.Rls();
if (!conn.Meta_idx_exists(tbl_name, "pkey"))
conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_blob_id, fld_wiki_id, fld_blob_tid));
}
public void Insert_by_rdr(Db_rdr rdr) {
Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert);
}
public void Insert_exec(int blob_tid, int wiki_id, int blob_id, byte[] blob_data) {
blob_data = zip_mgr.Zip(zip_tid_default, blob_data);
stmt_insert.Clear()
.Val_int(fld_blob_tid , blob_tid)
.Val_int(fld_wiki_id , wiki_id)
.Val_int(fld_blob_id , blob_id)
.Val_byte(fld_zip_tid , zip_tid_default)
.Val_bry(fld_blob_data , blob_data)
.Exec_insert();
}
public void Select_to_regy(Bry_bfr temp_bfr, Hash_adp_bry blob_data_hash) {
Db_rdr rdr = conn.Stmt_select(tbl_name, String_.Ary(fld_wiki_id, fld_blob_id, fld_blob_tid))
.Exec_select__rls_auto();
try {
while (rdr.Move_next()) {
byte[] key = Make_key(temp_bfr, rdr.Read_int(fld_wiki_id), rdr.Read_int(fld_blob_id), rdr.Read_int(fld_blob_tid));
blob_data_hash.Add_as_key_and_val(key);
}
} finally {
rdr.Rls();
}
}
public byte[] Select_text(int blob_tid, int wiki_id, int blob_id) {
Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_blob_id, fld_wiki_id, fld_blob_tid)
.Crt_int(fld_blob_id, blob_id)
.Crt_int(fld_wiki_id, wiki_id)
.Crt_int(fld_blob_tid, blob_tid)
.Exec_select__rls_auto();
try {
if (rdr.Move_next()) {
byte[] rv = rdr.Read_bry(fld_blob_data);
byte zip_type = rdr.Read_byte(fld_zip_tid);
rv = zip_mgr.Unzip(zip_type, rv);
return rv;
}
else {
return null;
}
} finally {
rdr.Rls();
}
}
public static byte[] Make_key(Bry_bfr temp_bfr, int blob_id, int wiki_id, int blob_tid) {
return temp_bfr.Add_int_variable(blob_id).Add_byte_pipe().Add_int_variable(wiki_id).Add_byte_pipe().Add_int_variable(blob_tid).To_bry_and_clear();
}
public static final int Blob_tid__wtxt = 0, Blob_tid__html = 1;
package gplx.xowa.htmls.hxtns.blobs;
import gplx.Bry_bfr;
import gplx.Hash_adp_bry;
import gplx.Rls_able;
import gplx.String_;
import gplx.core.ios.Io_stream_zip_mgr;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_rdr;
import gplx.dbs.Db_rdr_;
import gplx.dbs.Db_stmt;
import gplx.dbs.Db_stmt_;
import gplx.dbs.Dbmeta_fld_list;
import gplx.dbs.Dbmeta_idx_itm;
import gplx.dbs.Dbmeta_tbl_itm;
public class Hxtn_blob_tbl implements Rls_able {
private static final String tbl_name = "hxtn_blob"; private static final Dbmeta_fld_list flds = new Dbmeta_fld_list();
private static final String
fld_blob_tid = flds.Add_int("blob_tid"), fld_wiki_id = flds.Add_int("wiki_id"), fld_blob_id = flds.Add_int("blob_id")
, fld_zip_tid = flds.Add_byte("zip_tid"), fld_blob_data = flds.Add_bry("blob_data");
private final Db_conn conn; private Db_stmt stmt_insert;
private final byte zip_tid_default;
private final Io_stream_zip_mgr zip_mgr = new Io_stream_zip_mgr();
public Hxtn_blob_tbl(Db_conn conn, byte zip_tid_default) {
this.conn = conn;
conn.Rls_reg(this);
this.zip_tid_default = zip_tid_default;
}
public String Tbl_name() {return tbl_name;}
public Db_conn Conn() {return conn;}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public void Rls() {
stmt_insert = Db_stmt_.Rls(stmt_insert);
}
public void Stmt_bgn() {
stmt_insert = conn.Stmt_insert(tbl_name, flds);
}
public void Stmt_end() {
this.Rls();
if (!conn.Meta_idx_exists(tbl_name, "pkey"))
conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_blob_id, fld_wiki_id, fld_blob_tid));
}
public void Insert_by_rdr(Db_rdr rdr) {
Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert);
}
public void Insert_exec(int blob_tid, int wiki_id, int blob_id, byte[] blob_data) {
blob_data = zip_mgr.Zip(zip_tid_default, blob_data);
stmt_insert.Clear()
.Val_int(fld_blob_tid , blob_tid)
.Val_int(fld_wiki_id , wiki_id)
.Val_int(fld_blob_id , blob_id)
.Val_byte(fld_zip_tid , zip_tid_default)
.Val_bry(fld_blob_data , blob_data)
.Exec_insert();
}
public boolean Exists(int blob_tid, int wiki_id, int blob_id) {
Db_rdr rdr = Db_rdr_.Empty;
try {
rdr = conn.Stmt_select(tbl_name, flds, fld_blob_tid, fld_wiki_id, fld_blob_id)
.Crt_int(fld_blob_tid, blob_tid)
.Crt_int(fld_wiki_id, wiki_id)
.Crt_int(fld_blob_id, blob_id)
.Exec_select__rls_auto();
return rdr.Move_next();
} finally {
rdr.Rls();
}
}
public void Select_to_regy(Bry_bfr temp_bfr, Hash_adp_bry blob_data_hash) {
Db_rdr rdr = conn.Stmt_select(tbl_name, String_.Ary(fld_wiki_id, fld_blob_id, fld_blob_tid))
.Exec_select__rls_auto();
try {
while (rdr.Move_next()) {
byte[] key = Make_key(temp_bfr, rdr.Read_int(fld_wiki_id), rdr.Read_int(fld_blob_id), rdr.Read_int(fld_blob_tid));
blob_data_hash.Add_as_key_and_val(key);
}
} finally {
rdr.Rls();
}
}
public byte[] Select_text(int blob_tid, int wiki_id, int blob_id) {
Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_blob_id, fld_wiki_id, fld_blob_tid)
.Crt_int(fld_blob_id, blob_id)
.Crt_int(fld_wiki_id, wiki_id)
.Crt_int(fld_blob_tid, blob_tid)
.Exec_select__rls_auto();
try {
if (rdr.Move_next()) {
byte[] rv = rdr.Read_bry(fld_blob_data);
byte zip_type = rdr.Read_byte(fld_zip_tid);
rv = zip_mgr.Unzip(zip_type, rv);
return rv;
}
else {
return null;
}
} finally {
rdr.Rls();
}
}
public static byte[] Make_key(Bry_bfr temp_bfr, int blob_id, int wiki_id, int blob_tid) {
return temp_bfr.Add_int_variable(blob_id).Add_byte_pipe().Add_int_variable(wiki_id).Add_byte_pipe().Add_int_variable(blob_tid).To_bry_and_clear();
}
public static final int Blob_tid__wtxt = 0, Blob_tid__html = 1;
}

@ -1,122 +1,124 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.htmls.hxtns.pages;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Gfo_usr_dlg_;
import gplx.Hash_adp_bry;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.List_adp;
import gplx.core.lists.hashs.Hash_adp__int;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_conn_bldr;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xow_wiki;
import gplx.xowa.htmls.Xoh_page;
import gplx.xowa.htmls.hxtns.blobs.Hxtn_blob_tbl;
import gplx.xowa.htmls.hxtns.wikis.Hxtn_wiki_mgr;
import gplx.xowa.htmls.hxtns.wkrs.Hxtn_wkr_mgr;
public class Hxtn_page_mgr {
private Hxtn_page_tbl page_tbl;
private Hxtn_blob_tbl blob_tbl;
private Hash_adp_bry blob_hash;
private final Hash_adp__int wkrs = new Hash_adp__int();
private boolean dbs_missing = true;
private Bry_bfr temp_bfr;
public Hxtn_page_tbl Page_tbl() {return page_tbl;}
public Hxtn_blob_tbl Blob_tbl() {return blob_tbl;}
public void Init_by_xomp_wkr(Db_conn wkr_db_conn, byte zip_tid) {
// init tbls and other members
this.page_tbl = new Hxtn_page_tbl(wkr_db_conn);
this.blob_tbl = new Hxtn_blob_tbl(wkr_db_conn, zip_tid);
this.blob_hash = Hash_adp_bry.cs();
this.temp_bfr = Bry_bfr_.New();
// if tbl exists, xomp_resume has run; load known blobs to prevent dupes
if (wkr_db_conn.Meta_tbl_exists(page_tbl.Tbl_name())) {
blob_tbl.Select_to_regy(temp_bfr, blob_hash);
}
// else tbl doesn't exist, so create them
else {
page_tbl.Create_tbl();
blob_tbl.Create_tbl();
}
}
public void Init_by_wiki(Xow_wiki wiki, boolean is_merge) {
Io_url core_db_url = Make_url(wiki, "-html.hxtn-core.xowa");
if (!is_merge && !Io_mgr.Instance.ExistsFil(core_db_url)) return;
dbs_missing = false;
Db_conn page_conn = Db_conn_bldr.Instance.Get_or_new(core_db_url).Conn();
this.page_tbl = new Hxtn_page_tbl(page_conn);
Io_url blob_db_url = Make_url(wiki, "-html.hxtn-blob.xowa");
this.blob_tbl = new Hxtn_blob_tbl(Db_conn_bldr.Instance.Get_or_new(blob_db_url).Conn(), gplx.core.ios.streams.Io_stream_tid_.Tid__raw);
if (is_merge) {
page_tbl.Create_tbl();
blob_tbl.Create_tbl();
Hxtn_wkr_mgr wkr_mgr = new Hxtn_wkr_mgr();
wkr_mgr.Init_by_xomp_merge(page_conn);
Hxtn_wiki_mgr wiki_mgr = new Hxtn_wiki_mgr();
wiki_mgr.Init_by_xomp_merge(page_conn, wiki.Domain_str());
}
}
public void Insert_bgn(boolean is_merge) {
page_tbl.Stmt_bgn();
blob_tbl.Stmt_bgn();
}
public void Insert_end(boolean is_merge) {
page_tbl.Stmt_end();
blob_tbl.Stmt_end();
}
public void Page_tbl__insert(int page_id, int wkr_id, int data_id) {
page_tbl.Insert_exec(page_id, wkr_id, data_id);
}
public void Blob_tbl__insert(int blob_tid, int wiki_id, int blob_id, byte[] blob_text) {
byte[] key = Hxtn_blob_tbl.Make_key(temp_bfr, blob_tid, wiki_id, blob_id);
if (!blob_hash.Has(key)) {// multiple pages can refer to same template; only insert if not seen
blob_hash.Add_as_key_and_val(key);
blob_tbl.Insert_exec(blob_tid, wiki_id, blob_id, blob_text);
}
}
public void Reg_wkr(Hxtn_page_wkr wkr) {
wkrs.Add(wkr.Id(), wkr);
}
public void Load_by_page(Xoh_page hpg, Xoa_ttl ttl) {
if (dbs_missing) return; // PERF:do not call SELECT if dbs don't exist
List_adp list = page_tbl.Select_by_page(hpg.Page_id());
int len = list.Len();
for (int i = 0; i < len; i++) {
Hxtn_page_itm itm = (Hxtn_page_itm)list.Get_at(i);
Hxtn_page_wkr wkr = (Hxtn_page_wkr)wkrs.Get_by_or_null(itm.Wkr_id());
if (wkr == null) { // ignore unknown wkrs so other devs can add new xtns; ISSUE#:634; DATE:2020-03-08
Gfo_usr_dlg_.Instance.Warn_many("", "", "hxtn.unknown wkr: page_id=~{0} wkr_id=~{1}", itm.Page_id(), itm.Wkr_id());
continue;
}
wkr.Load_by_page(hpg, ttl, itm.Data_id());
}
}
private static Io_url Make_url(Xow_wiki wiki, String file_name) {return wiki.Fsys_mgr().Root_dir().GenSubFil(wiki.Domain_str() + file_name);}
public static final int
Id__template_styles = 0
, Id__indicators = 2
;
}
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.htmls.hxtns.pages;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Gfo_usr_dlg_;
import gplx.Hash_adp_bry;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.List_adp;
import gplx.core.lists.hashs.Hash_adp__int;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_conn_bldr;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xow_wiki;
import gplx.xowa.htmls.Xoh_page;
import gplx.xowa.htmls.hxtns.blobs.Hxtn_blob_tbl;
import gplx.xowa.htmls.hxtns.wikis.Hxtn_wiki_mgr;
import gplx.xowa.htmls.hxtns.wkrs.Hxtn_wkr_mgr;
public class Hxtn_page_mgr {
private Hxtn_page_tbl page_tbl;
private Hxtn_blob_tbl blob_tbl;
private Hash_adp_bry blob_hash = Hash_adp_bry.cs();
private final Hash_adp__int wkrs = new Hash_adp__int();
private boolean dbs_missing = true;
private Bry_bfr temp_bfr = Bry_bfr_.New();
public Hxtn_page_tbl Page_tbl() {return page_tbl;}
public Hxtn_blob_tbl Blob_tbl() {return blob_tbl;}
public void Init_by_xomp_wkr(Db_conn wkr_db_conn, byte zip_tid) {
// init tbls and other members
this.page_tbl = new Hxtn_page_tbl(wkr_db_conn);
this.blob_tbl = new Hxtn_blob_tbl(wkr_db_conn, zip_tid);
// if tbl exists, xomp_resume has run; load known blobs to prevent dupes
if (wkr_db_conn.Meta_tbl_exists(page_tbl.Tbl_name())) {
blob_tbl.Select_to_regy(temp_bfr, blob_hash);
}
// else tbl doesn't exist, so create them
else {
page_tbl.Create_tbl();
blob_tbl.Create_tbl();
}
}
public void Init_by_wiki(Xow_wiki wiki, boolean is_merge) {
Io_url core_db_url = Make_url(wiki, "-html.hxtn-core.xowa");
if (!is_merge && !Io_mgr.Instance.ExistsFil(core_db_url)) return;
dbs_missing = false;
Db_conn page_conn = Db_conn_bldr.Instance.Get_or_new(core_db_url).Conn();
this.page_tbl = new Hxtn_page_tbl(page_conn);
Io_url blob_db_url = Make_url(wiki, "-html.hxtn-blob.xowa");
this.blob_tbl = new Hxtn_blob_tbl(Db_conn_bldr.Instance.Get_or_new(blob_db_url).Conn(), gplx.core.ios.streams.Io_stream_tid_.Tid__raw);
if (is_merge) {
page_tbl.Create_tbl();
blob_tbl.Create_tbl();
Hxtn_wkr_mgr wkr_mgr = new Hxtn_wkr_mgr();
wkr_mgr.Init_by_xomp_merge(page_conn);
Hxtn_wiki_mgr wiki_mgr = new Hxtn_wiki_mgr();
wiki_mgr.Init_by_xomp_merge(page_conn, wiki.Domain_str());
}
}
public void Insert_bgn(boolean is_merge) {
page_tbl.Stmt_bgn();
blob_tbl.Stmt_bgn();
}
public void Insert_end(boolean is_merge) {
page_tbl.Stmt_end();
blob_tbl.Stmt_end();
}
public void Page_tbl__insert(int page_id, int wkr_id, int data_id) {
if (!page_tbl.Exists(page_id, wkr_id, data_id))
page_tbl.Insert_exec(page_id, wkr_id, data_id);
}
public void Blob_tbl__insert(int blob_tid, int wiki_id, int blob_id, byte[] blob_text) {
byte[] key = Hxtn_blob_tbl.Make_key(temp_bfr, blob_tid, wiki_id, blob_id);
if (!blob_hash.Has(key)) {// multiple pages can refer to same template; only insert if not seen
blob_hash.Add_as_key_and_val(key);
if (!blob_tbl.Exists(blob_tid, wiki_id, blob_id)) {
blob_tbl.Insert_exec(blob_tid, wiki_id, blob_id, blob_text);
}
}
}
public void Reg_wkr(Hxtn_page_wkr wkr) {
wkrs.Add(wkr.Id(), wkr);
}
public void Load_by_page(Xoh_page hpg, Xoa_ttl ttl) {
if (dbs_missing) return; // PERF:do not call SELECT if dbs don't exist
List_adp list = page_tbl.Select_by_page(hpg.Page_id());
int len = list.Len();
for (int i = 0; i < len; i++) {
Hxtn_page_itm itm = (Hxtn_page_itm)list.Get_at(i);
Hxtn_page_wkr wkr = (Hxtn_page_wkr)wkrs.Get_by_or_null(itm.Wkr_id());
if (wkr == null) { // ignore unknown wkrs so other devs can add new xtns; ISSUE#:634; DATE:2020-03-08
Gfo_usr_dlg_.Instance.Warn_many("", "", "hxtn.unknown wkr: page_id=~{0} wkr_id=~{1}", itm.Page_id(), itm.Wkr_id());
continue;
}
wkr.Load_by_page(hpg, ttl, itm.Data_id());
}
}
private static Io_url Make_url(Xow_wiki wiki, String file_name) {return wiki.Fsys_mgr().Root_dir().GenSubFil(wiki.Domain_str() + file_name);}
public static final int
Id__template_styles = 0
, Id__indicators = 2
;
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,57 +13,82 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.htmls.hxtns.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.htmls.*; import gplx.xowa.htmls.hxtns.*;
import gplx.dbs.*;
public class Hxtn_page_tbl implements Rls_able {
private static final String tbl_name = "hxtn_page"; private final Dbmeta_fld_list flds = new Dbmeta_fld_list();
private final String fld_page_id, fld_wkr_id, fld_data_id;
private final Db_conn conn; private Db_stmt stmt_insert;
public Hxtn_page_tbl(Db_conn conn) {
this.conn = conn;
conn.Rls_reg(this);
flds.Add_int_pkey_autonum("id");
this.fld_page_id = flds.Add_int("page_id");
this.fld_wkr_id = flds.Add_int("wkr_id");
this.fld_data_id = flds.Add_int("data_id");
}
public String Tbl_name() {return tbl_name;}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public Db_conn Conn() {return conn;}
public void Rls() {
stmt_insert = Db_stmt_.Rls(stmt_insert);
}
public void Stmt_bgn() {
stmt_insert = conn.Stmt_insert(tbl_name, flds);
}
public void Stmt_end() {
this.Rls();
if (!conn.Meta_idx_exists(tbl_name, "pkey"))
conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_page_id, fld_wkr_id, fld_data_id));
}
public void Insert_by_rdr(Db_rdr rdr) {
Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert);
}
public void Insert_exec(int page_id, int wkr_id, int data_id) {
stmt_insert.Clear()
.Val_int(fld_page_id , page_id)
.Val_int(fld_wkr_id , wkr_id)
.Val_int(fld_data_id , data_id)
.Exec_insert();
}
public List_adp Select_by_page(int page_id) {
List_adp rv = List_adp_.New();
Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_page_id)
.Crt_int(fld_page_id, page_id)
.Exec_select__rls_auto();
try {
while (rdr.Move_next()) {
Hxtn_page_itm itm = new Hxtn_page_itm(rdr.Read_int(fld_page_id), rdr.Read_int(fld_wkr_id), rdr.Read_int(fld_data_id));
rv.Add(itm);
}
} finally {
rdr.Rls();
}
return rv;
}
}
package gplx.xowa.htmls.hxtns.pages;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Rls_able;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_rdr;
import gplx.dbs.Db_rdr_;
import gplx.dbs.Db_stmt;
import gplx.dbs.Db_stmt_;
import gplx.dbs.Dbmeta_fld_list;
import gplx.dbs.Dbmeta_idx_itm;
import gplx.dbs.Dbmeta_tbl_itm;
public class Hxtn_page_tbl implements Rls_able {
private static final String tbl_name = "hxtn_page"; private final Dbmeta_fld_list flds = new Dbmeta_fld_list();
private final String fld_page_id, fld_wkr_id, fld_data_id;
private final Db_conn conn; private Db_stmt stmt_insert;
public Hxtn_page_tbl(Db_conn conn) {
this.conn = conn;
conn.Rls_reg(this);
flds.Add_int_pkey_autonum("id");
this.fld_page_id = flds.Add_int("page_id");
this.fld_wkr_id = flds.Add_int("wkr_id");
this.fld_data_id = flds.Add_int("data_id");
}
public String Tbl_name() {return tbl_name;}
public void Create_tbl() {conn.Meta_tbl_create(Dbmeta_tbl_itm.New(tbl_name, flds));}
public Db_conn Conn() {return conn;}
public void Rls() {
stmt_insert = Db_stmt_.Rls(stmt_insert);
}
public void Stmt_bgn() {
stmt_insert = conn.Stmt_insert(tbl_name, flds);
}
public void Stmt_end() {
this.Rls();
if (!conn.Meta_idx_exists(tbl_name, "pkey"))
conn.Meta_idx_create(Dbmeta_idx_itm.new_unique_by_tbl(tbl_name, "pkey", fld_page_id, fld_wkr_id, fld_data_id));
}
public void Insert_by_rdr(Db_rdr rdr) {
Db_stmt_.Insert_by_rdr(flds, rdr, stmt_insert);
}
public void Insert_exec(int page_id, int wkr_id, int data_id) {
stmt_insert.Clear()
.Val_int(fld_page_id , page_id)
.Val_int(fld_wkr_id , wkr_id)
.Val_int(fld_data_id , data_id)
.Exec_insert();
}
public boolean Exists(int page_id, int wkr_id, int data_id) {
Db_rdr rdr = Db_rdr_.Empty;
try {
rdr = conn.Stmt_select(tbl_name, flds, fld_page_id, fld_wkr_id, fld_data_id)
.Crt_int(fld_page_id, page_id)
.Crt_int(fld_wkr_id, wkr_id)
.Crt_int(fld_data_id, data_id)
.Exec_select__rls_auto();
return rdr.Move_next();
} finally {
rdr.Rls();
}
}
public List_adp Select_by_page(int page_id) {
List_adp rv = List_adp_.New();
Db_rdr rdr = conn.Stmt_select(tbl_name, flds, fld_page_id)
.Crt_int(fld_page_id, page_id)
.Exec_select__rls_auto();
try {
while (rdr.Move_next()) {
Hxtn_page_itm itm = new Hxtn_page_itm(rdr.Read_int(fld_page_id), rdr.Read_int(fld_wkr_id), rdr.Read_int(fld_data_id));
rv.Add(itm);
}
} finally {
rdr.Rls();
}
return rv;
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,49 +13,52 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
public class Xow_db_file_ {
public static final int Uid__core = 0;
public static final byte
Tid__core = 1, Tid__text = 2, Tid__cat = 3, Tid__search_core = 4, Tid__wbase = 5 // SERIALIZED:v1
, Tid__cat_core = 6, Tid__cat_link = 7 // SERIALIZED:v2
, Tid__wiki_solo = 8, Tid__text_solo = 9
, Tid__html_solo = 10, Tid__html_data = 11
, Tid__file_solo = 12, Tid__file_core = 13, Tid__file_data = 14, Tid__file_user = 15
, Tid__search_link = 16, Tid__random = 17, Tid__css = 18
, Tid__html_user = 19
;
private static final String
Key__core = "core", Key__text = "text", Key__cat = "xtn.category", Key__search_core = "xtn.search.core", Key__wbase = "core.wbase"
, Key__cat_core = "xtn.category.core", Key__cat_link = "xtn.category.link"
, Key__text_solo = "text.solo", Key__wiki_solo = "wiki.solo"
, Key__html_solo = "html.solo", Key__html_data = "html"
, Key__file_solo = "file.solo", Key__file_core = "file.core", Key__file_data = "file.data", Key__file_user = "file.user"
, Key__search_link = "xtn.search.link", Key__random = "xtn.random", Key__css = "xtn.css"
, Key__html_user = "html.user"
;
public static String To_key(byte v) {
switch (v) {
case Tid__core: return Key__core;
case Tid__text: return Key__text;
case Tid__cat: return Key__cat;
case Tid__search_core: return Key__search_core;
case Tid__wbase: return Key__wbase;
case Tid__cat_core: return Key__cat_core;
case Tid__cat_link: return Key__cat_link;
case Tid__wiki_solo: return Key__wiki_solo;
case Tid__text_solo: return Key__text_solo;
case Tid__html_solo: return Key__html_solo;
case Tid__html_data: return Key__html_data;
case Tid__file_solo: return Key__file_solo;
case Tid__file_core: return Key__file_core;
case Tid__file_data: return Key__file_data;
case Tid__file_user: return Key__file_user;
case Tid__search_link: return Key__search_link;
case Tid__random: return Key__random;
case Tid__css: return Key__css;
case Tid__html_user: return Key__html_user;
default: throw Err_.new_unhandled(v);
}
}
}
package gplx.xowa.wikis.data;
import gplx.Err_;
public class Xow_db_file_ {
public static final int Uid__core = 0;
public static final byte
Tid__core = 1, Tid__text = 2, Tid__cat = 3, Tid__search_core = 4, Tid__wbase = 5 // SERIALIZED:v1
, Tid__cat_core = 6, Tid__cat_link = 7 // SERIALIZED:v2
, Tid__wiki_solo = 8, Tid__text_solo = 9
, Tid__html_solo = 10, Tid__html_data = 11
, Tid__file_solo = 12, Tid__file_core = 13, Tid__file_data = 14, Tid__file_user = 15
, Tid__search_link = 16, Tid__random = 17, Tid__css = 18
, Tid__html_user = 19
;
private static final String
Key__core = "core", Key__text = "text", Key__cat = "xtn.category", Key__search_core = "xtn.search.core", Key__wbase = "core.wbase"
, Key__cat_core = "xtn.category.core", Key__cat_link = "xtn.category.link"
, Key__text_solo = "text.solo", Key__wiki_solo = "wiki.solo"
, Key__html_solo = "html.solo", Key__html_data = "html"
, Key__file_solo = "file.solo", Key__file_core = "file.core", Key__file_data = "file.data", Key__file_user = "file.user"
, Key__search_link = "xtn.search.link", Key__random = "xtn.random", Key__css = "xtn.css"
, Key__html_user = "html.user"
;
public static String To_key(byte v) {
switch (v) {
case Tid__core: return Key__core;
case Tid__text: return Key__text;
case Tid__cat: return Key__cat;
case Tid__search_core: return Key__search_core;
case Tid__wbase: return Key__wbase;
case Tid__cat_core: return Key__cat_core;
case Tid__cat_link: return Key__cat_link;
case Tid__wiki_solo: return Key__wiki_solo;
case Tid__text_solo: return Key__text_solo;
case Tid__html_solo: return Key__html_solo;
case Tid__html_data: return Key__html_data;
case Tid__file_solo: return Key__file_solo;
case Tid__file_core: return Key__file_core;
case Tid__file_data: return Key__file_data;
case Tid__file_user: return Key__file_user;
case Tid__search_link: return Key__search_link;
case Tid__random: return Key__random;
case Tid__css: return Key__css;
case Tid__html_user: return Key__html_user;
default: throw Err_.new_unhandled(v);
}
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,218 +13,240 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.data; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
import gplx.dbs.*; import gplx.dbs.cfgs.*; import gplx.core.lists.hashs.*;
import gplx.xowa.wikis.dbs.*; import gplx.xowa.wikis.data.tbls.*;
import gplx.xowa.wikis.domains.*; import gplx.xowa.bldrs.infos.*; import gplx.xowa.wikis.metas.*;
public class Xow_db_mgr {
private final Io_url wiki_root_dir;
private final String domain_str; // needed for generating new files; EX: en.wikipedia.org-text.ns.001.xowa
private final Ordered_hash hash_by_id = Ordered_hash_.New(); private final Xow_db_file_hash hash_by_tids = new Xow_db_file_hash();
private int db_id_next = 0;
public Xow_db_mgr(Io_url wiki_root_dir, String domain_str) {
this.wiki_root_dir = wiki_root_dir;
this.domain_str = domain_str;
}
public Xowd_core_db_props Props() {return props;} private Xowd_core_db_props props = Xowd_core_db_props.Test;
public Db_cfg_tbl Tbl__cfg() {return db__core.Tbl__cfg();}
public Xowd_page_tbl Tbl__page() {return db__core.Tbl__page();}
public Xow_db_file Db__core() {return db__core;} private Xow_db_file db__core;
public Xow_db_file Db__text() {return db__text;} private Xow_db_file db__text;
public Xow_db_file Db__html() {return db__html;} private Xow_db_file db__html;
public Xow_db_file Db__cat_core() {return db__cat_core;} private Xow_db_file db__cat_core;
public Xow_db_file Db__wbase() {return db__wbase;} private Xow_db_file db__wbase; public void Db__wbase_(Xow_db_file v) {db__wbase = v;}
public void Init_by_load(Io_url core_url) {
// clear lists
hash_by_id.Clear();
hash_by_tids.Clear();
// create core_conn / core_db
Db_conn core_conn = Db_conn_bldr.Instance.Get(core_url);
props = Xowd_core_db_props.Cfg_load(core_conn); // load props to get layout_text
Dbs__set_by_tid(Xow_db_file.Load(props, Xow_db_file_.Uid__core, Xow_db_file__core_.Core_db_tid(props.Layout_text()), core_url, Xob_info_file.Ns_ids_empty, Xob_info_file.Part_id_1st, Guid_adp_.Empty));
// load dbs from "xowa_db" tbl
Xow_db_file[] ary = db__core.Tbl__db().Select_all(props, core_url.OwnerDir());
int len = ary.length;
for (int i = 0; i < len; i++) {
Xow_db_file db = ary[i];
Dbs__set_by_tid(db);
Dbs__add(db);
}
}
public void Init_by_make(Xowd_core_db_props props, Xob_info_session info_session) {
this.props = props;
// save data
Xow_db_file core_db = Xow_db_file__core_.Make_core_db(props, info_session, wiki_root_dir, domain_str);
Dbs__set_by_tid(core_db);
Dbs__add_and_save(core_db);
props.Cfg_save(db__core.Tbl__cfg()); // NOTE: must save cfg now, especially zip_tid; latter will be reloaded after import is done;
}
public void Rls() {
int len = hash_by_id.Len();
for (int i = 0; i < len; i++) {
Xow_db_file db_file = (Xow_db_file)hash_by_id.Get_at(i);
db_file.Rls();
}
}
public int Dbs__len() {return hash_by_id.Len();}
public Xow_db_file Dbs__get_at(int i) {return (Xow_db_file)hash_by_id.Get_at(i);}
public Xow_db_file Dbs__get_by_id_or_fail(int id) {return (Xow_db_file)hash_by_id.Get_by_or_fail(id);}
public Xow_db_file Dbs__get_by_id_or_null(int id) {return (Xow_db_file)hash_by_id.Get_by(id);}
public Xow_db_file Dbs__get_by_tid_or_core(byte... tids_ary) {Xow_db_file rv = Dbs__get_by_tid_or_null(tids_ary); return rv == null ? db__core : rv;}
public Xow_db_file Dbs__get_by_tid_or_null(byte... tids_ary) {
int tids_len = tids_ary.length;
for (int i = 0; i < tids_len; ++i) {
byte tid = tids_ary[i];
Ordered_hash tid_dbs = hash_by_tids.Get_by_tid_or_null(tid); if (tid_dbs == null) continue;
int tid_dbs_len = tid_dbs.Len();
if (tid_dbs_len != 1) { // NOTE: occurs when multiple search imports fail; DATE:2016-04-04
Xoa_app_.Usr_dlg().Warn_many("", "", "expecting only 1 db for tid; tid=~{0} len=~{1} db_api=~{2}", tid, tid_dbs.Len(), db__core.Conn().Conn_info().Db_api());
}
return (Xow_db_file)tid_dbs.Get_at(tid_dbs_len - 1); // get last idx;
}
return null;
}
public Xow_db_file Dbs__assert_by_tid(byte tid) {
Xow_db_file rv = Dbs__get_by_tid_or_null(tid);
if (rv == null) {
rv = Dbs__make_by_tid(tid);
}
return rv;
}
public Ordered_hash Dbs__get_hash_by_tid(int tid) {return hash_by_tids.Get_by_tid_or_null((byte)tid);}
public Xow_db_file Dbs__make_by_tid(byte tid) {
int tid_idx = Get_tid_idx(hash_by_tids, tid);
return Dbs__make_by_tid(tid, Xob_info_file.Ns_ids_empty, tid_idx, Get_tid_name(tid_idx, tid));
}
public Xow_db_file Dbs__make_by_tid(byte tid, String ns_ids, int part_id, String file_name_suffix) {
return Dbs__make_by_id(db_id_next++, tid, ns_ids, part_id, file_name_suffix);
}
public Xow_db_file Dbs__make_by_id(int id, byte tid, String ns_ids, int part_id, String file_name_suffix) {
Io_url url = wiki_root_dir.GenSubFil(domain_str + file_name_suffix);
Xow_db_file rv = Xow_db_file.Make(db__core.Info_session(), props, id, tid, url, ns_ids, part_id, db__core.Url().NameAndExt(), Db_conn_bldr.Instance.New(url));
Dbs__add_and_save(rv);
Dbs__set_by_tid(rv);
return rv;
}
public Xow_db_file Dbs__remake_by_tid(byte tid) {
Dbs__delete_by_tid(tid);
return Dbs__make_by_tid(tid);
}
public void Dbs__delete_by_tid(byte... tids) {
int len = hash_by_id.Len();
for (int i = 0; i < len; ++i) {
Xow_db_file db = (Xow_db_file)hash_by_id.Get_at(i);
if (!Byte_.Match_any(db.Tid(), tids)) continue;
db.Rls();
Io_mgr.Instance.DeleteFil_args(db.Url()).MissingFails_off().Exec();
db.Cmd_mode_(Db_cmd_mode.Tid_delete);
}
db__core.Tbl__db().Commit_all(this);
// call init again to regen list of dbs
this.Init_by_load(db__core.Url());
}
public Xow_db_file Dbs__get_for_create(byte tid, int ns_id) {
Xow_db_file[] ary = Dbs__get_ary(tid, ns_id);
if (ary.length == 0) throw Err_.new_wo_type("no dbs exist; wiki=~{0} type=~{1}", domain_str, tid);
return ary[ary.length - 1];
}
public Xow_db_file[] Dbs__get_ary(byte tid, int ns_id) {
List_adp rv = List_adp_.New();
// loop all dbs
int len = this.Dbs__len();
for (int i = 0; i < len; i++) {
boolean add = false;
Xow_db_file db = this.Dbs__get_at(i);
switch (tid) {
// cat_link requested
case Xow_db_file_.Tid__cat_link:
switch (db.Tid()) {
case Xow_db_file_.Tid__core:
add = props.Layout_text().Tid_is_all_or_few(); // cat_link will be in "core" if "all" or "few" (-text, -html, -file)
break;
case Xow_db_file_.Tid__cat_link:
add = true;
break;
}
break;
// text requested
case Xow_db_file_.Tid__text:
switch (db.Tid()) {
case Xow_db_file_.Tid__core:
add = props.Layout_text().Tid_is_all(); // text will be in "core" if "all"
break;
case Xow_db_file_.Tid__text_solo: // EX: "en.wikipedia.org-text.xowa"
add = true; // text will be in db if solo;
break;
case Xow_db_file_.Tid__text: // EX: "en.wikipedia.org-text-ns.000.xowa"
int[] db_ns_ids = Int_ary_.Parse(db.Ns_ids(), "|"); // need to handle both "0" and "0|4"
for (int db_ns_id : db_ns_ids) {
if (db_ns_id == ns_id) {
add = true; // text will be in db if ns matches; EX: en.wikipedia.org-text-ns.014.xowa
break;
}
}
break;
}
break;
}
if (add)
rv.Add(db);
}
return (Xow_db_file[])rv.To_ary_and_clear(Xow_db_file.class);
}
public void Create_page(Xowd_page_tbl core_tbl, Xowd_text_tbl text_tbl, int page_id, int ns_id, byte[] ttl_wo_ns, boolean redirect, DateAdp modified_on, byte[] text_zip_data, int text_raw_len, int random_int, int text_db_id, int html_db_id) {
core_tbl.Insert_cmd_by_batch(page_id, ns_id, ttl_wo_ns, redirect, modified_on, text_raw_len, random_int, text_db_id, html_db_id, -1);
text_tbl.Insert_cmd_by_batch(page_id, text_zip_data);
}
private void Dbs__set_by_tid(Xow_db_file db) {
switch (db.Tid()) {
case Xow_db_file_.Tid__wiki_solo:
case Xow_db_file_.Tid__text_solo:
case Xow_db_file_.Tid__core : {db__core = db; if (props.Layout_text().Tid_is_all_or_few()) db__cat_core = db__text = db; break;}
case Xow_db_file_.Tid__text : {db__text = db; break;}
case Xow_db_file_.Tid__html_data : {db__html = db; break;}
case Xow_db_file_.Tid__wbase : {if (db__wbase == null) db__wbase = db; break;}
case Xow_db_file_.Tid__cat_core :
case Xow_db_file_.Tid__cat : {if (db__cat_core == null) db__cat_core = db; break;}
}
}
private void Dbs__add(Xow_db_file db_file) {
int db_id = db_file.Id();
hash_by_id.Add(db_id, db_file);
hash_by_tids.Add_or_new(db_file);
if (db_id >= db_id_next) // always set db_id_next to largest value in given set of dbs; EX: dbs=[0,1,10]; db_id_next should be 11
db_id_next = db_id + 1;
}
private void Dbs__add_and_save(Xow_db_file db_file) {
Dbs__add(db_file);
db__core.Tbl__db().Commit_all(this);
db_file.Info_file().Save(db_file.Tbl__cfg());
db_file.Info_session().Save(db_file.Tbl__cfg());
}
private int Get_tid_idx(Xow_db_file_hash hash, byte tid) {return hash.Count_of_tid(tid) + Int_.Base1;}
private static String Get_tid_name(int tid_idx, byte tid) {
String tid_name = Xow_db_file_.To_key(tid);
String tid_idx_str = "";
switch (tid) {
case Xow_db_file_.Tid__cat_core : break;
case Xow_db_file_.Tid__cat_link : tid_idx_str = "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break;
default : tid_idx_str = tid_idx == 1 ? "" : "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break;
}
return String_.Format("-{0}{1}.xowa", tid_name, tid_idx_str); // EX: en.wikipedia.org-text-001.sqlite3
}
// helper method for wikis to (a) init db_mgr; (b) load wiki.props; should probably be moved to more generic "wiki.Init_by_db()"
public static void Init_by_load(Xow_wiki wiki, Io_url core_url) {
wiki.Data__core_mgr().Init_by_load(core_url);
wiki.Props().Init_by_load(wiki.App(), wiki.Data__core_mgr().Tbl__cfg()); // load Main_page
}
}
package gplx.xowa.wikis.data;
import gplx.Byte_;
import gplx.DateAdp;
import gplx.Err_;
import gplx.Guid_adp_;
import gplx.Int_;
import gplx.Int_ary_;
import gplx.Io_mgr;
import gplx.Io_url;
import gplx.List_adp;
import gplx.List_adp_;
import gplx.Ordered_hash;
import gplx.Ordered_hash_;
import gplx.String_;
import gplx.dbs.Db_cmd_mode;
import gplx.dbs.Db_conn;
import gplx.dbs.Db_conn_bldr;
import gplx.dbs.cfgs.Db_cfg_tbl;
import gplx.xowa.Xoa_app_;
import gplx.xowa.Xow_wiki;
import gplx.xowa.bldrs.infos.Xob_info_file;
import gplx.xowa.bldrs.infos.Xob_info_session;
import gplx.xowa.wikis.data.tbls.Xowd_page_tbl;
import gplx.xowa.wikis.data.tbls.Xowd_text_tbl;
public class Xow_db_mgr {
private final Io_url wiki_root_dir;
private final String domain_str; // needed for generating new files; EX: en.wikipedia.org-text.ns.001.xowa
private final Ordered_hash hash_by_id = Ordered_hash_.New(); private final Xow_db_file_hash hash_by_tids = new Xow_db_file_hash();
private int db_id_next = 0;
public Xow_db_mgr(Io_url wiki_root_dir, String domain_str) {
this.wiki_root_dir = wiki_root_dir;
this.domain_str = domain_str;
}
public Xowd_core_db_props Props() {return props;} private Xowd_core_db_props props = Xowd_core_db_props.Test;
public Db_cfg_tbl Tbl__cfg() {return db__core.Tbl__cfg();}
public Xowd_page_tbl Tbl__page() {return db__core.Tbl__page();}
public Xow_db_file Db__core() {return db__core;} private Xow_db_file db__core;
public Xow_db_file Db__text() {return db__text;} private Xow_db_file db__text;
public Xow_db_file Db__html() {return db__html;} private Xow_db_file db__html;
public Xow_db_file Db__cat_core() {return db__cat_core;} private Xow_db_file db__cat_core;
public Xow_db_file Db__wbase() {return db__wbase;} private Xow_db_file db__wbase; public void Db__wbase_(Xow_db_file v) {db__wbase = v;}
public void Init_by_load(Io_url core_url) {
// clear lists
hash_by_id.Clear();
hash_by_tids.Clear();
// create core_conn / core_db
Db_conn core_conn = Db_conn_bldr.Instance.Get(core_url);
props = Xowd_core_db_props.Cfg_load(core_conn); // load props to get layout_text
Dbs__set_by_tid(Xow_db_file.Load(props, Xow_db_file_.Uid__core, Xow_db_file__core_.Core_db_tid(props.Layout_text()), core_url, Xob_info_file.Ns_ids_empty, Xob_info_file.Part_id_1st, Guid_adp_.Empty));
// load dbs from "xowa_db" tbl
Xow_db_file[] ary = db__core.Tbl__db().Select_all(props, core_url.OwnerDir());
int len = ary.length;
for (int i = 0; i < len; i++) {
Xow_db_file db = ary[i];
Dbs__set_by_tid(db);
Dbs__add(db);
}
}
public void Init_by_make(Xowd_core_db_props props, Xob_info_session info_session) {
this.props = props;
// save data
Xow_db_file core_db = Xow_db_file__core_.Make_core_db(props, info_session, wiki_root_dir, domain_str);
Dbs__set_by_tid(core_db);
Dbs__add_and_save(core_db);
props.Cfg_save(db__core.Tbl__cfg()); // NOTE: must save cfg now, especially zip_tid; latter will be reloaded after import is done;
}
public void Rls() {
int len = hash_by_id.Len();
for (int i = 0; i < len; i++) {
Xow_db_file db_file = (Xow_db_file)hash_by_id.Get_at(i);
db_file.Rls();
}
}
public int Dbs__len() {return hash_by_id.Len();}
public Xow_db_file Dbs__get_at(int i) {return (Xow_db_file)hash_by_id.Get_at(i);}
public Xow_db_file Dbs__get_by_id_or_fail(int id) {return (Xow_db_file)hash_by_id.Get_by_or_fail(id);}
public Xow_db_file Dbs__get_by_id_or_null(int id) {return (Xow_db_file)hash_by_id.Get_by(id);}
public Xow_db_file Dbs__get_by_tid_or_core(byte... tids_ary) {Xow_db_file rv = Dbs__get_by_tid_or_null(tids_ary); return rv == null ? db__core : rv;}
public Xow_db_file Dbs__get_by_tid_or_null(byte... tids_ary) {
int tids_len = tids_ary.length;
for (int i = 0; i < tids_len; ++i) {
byte tid = tids_ary[i];
Ordered_hash tid_dbs = hash_by_tids.Get_by_tid_or_null(tid); if (tid_dbs == null) continue;
int tid_dbs_len = tid_dbs.Len();
if (tid_dbs_len != 1) { // NOTE: occurs when multiple search imports fail; DATE:2016-04-04
Xoa_app_.Usr_dlg().Warn_many("", "", "expecting only 1 db for tid; tid=~{0} len=~{1} db_api=~{2}", tid, tid_dbs.Len(), db__core.Conn().Conn_info().Db_api());
}
return (Xow_db_file)tid_dbs.Get_at(tid_dbs_len - 1); // get last idx;
}
return null;
}
public Xow_db_file Dbs__assert_by_tid(byte tid) {
Xow_db_file rv = Dbs__get_by_tid_or_null(tid);
if (rv == null) {
rv = Dbs__make_by_tid(tid);
}
return rv;
}
public Ordered_hash Dbs__get_hash_by_tid(int tid) {return hash_by_tids.Get_by_tid_or_null((byte)tid);}
public Xow_db_file Dbs__make_by_tid(byte tid) {
int tid_idx = Get_tid_idx(hash_by_tids, tid);
return Dbs__make_by_tid(tid, Xob_info_file.Ns_ids_empty, tid_idx, Get_tid_name(tid_idx, tid));
}
public Xow_db_file Dbs__make_by_tid(byte tid, String ns_ids, int part_id, String file_name_suffix) {
return Dbs__make_by_id(db_id_next++, tid, ns_ids, part_id, file_name_suffix);
}
public Xow_db_file Dbs__make_by_id(int id, byte tid, String ns_ids, int part_id, String file_name_suffix) {
Io_url url = wiki_root_dir.GenSubFil(domain_str + file_name_suffix);
Xow_db_file rv = Xow_db_file.Make(db__core.Info_session(), props, id, tid, url, ns_ids, part_id, db__core.Url().NameAndExt(), Db_conn_bldr.Instance.New(url));
Dbs__add_and_save(rv);
Dbs__set_by_tid(rv);
return rv;
}
public Xow_db_file Dbs__remake_by_tid(byte tid) {
Dbs__delete_by_tid(tid);
return Dbs__make_by_tid(tid);
}
public void Dbs__delete_by_tid(byte... tids) {
int len = hash_by_id.Len();
for (int i = 0; i < len; ++i) {
Xow_db_file db = (Xow_db_file)hash_by_id.Get_at(i);
if (!Byte_.Match_any(db.Tid(), tids)) continue;
db.Rls();
Io_mgr.Instance.DeleteFil_args(db.Url()).MissingFails_off().Exec();
db.Cmd_mode_(Db_cmd_mode.Tid_delete);
}
db__core.Tbl__db().Commit_all(this);
// call init again to regen list of dbs
this.Init_by_load(db__core.Url());
}
public Xow_db_file Dbs__get_for_create(byte tid, int ns_id) {
Xow_db_file[] ary = Dbs__get_ary(tid, ns_id);
if (ary.length == 0) throw Err_.new_wo_type("no dbs exist; wiki=~{0} type=~{1}", domain_str, tid);
return ary[ary.length - 1];
}
public Xow_db_file[] Dbs__get_ary(byte tid, int ns_id) {
List_adp rv = List_adp_.New();
// loop all dbs
int len = this.Dbs__len();
for (int i = 0; i < len; i++) {
boolean add = false;
Xow_db_file db = this.Dbs__get_at(i);
switch (tid) {
// cat_link requested
case Xow_db_file_.Tid__cat_link:
switch (db.Tid()) {
case Xow_db_file_.Tid__core:
add = props.Layout_text().Tid_is_all_or_few(); // cat_link will be in "core" if "all" or "few" (-text, -html, -file)
break;
case Xow_db_file_.Tid__cat_link:
add = true;
break;
}
break;
// text requested
case Xow_db_file_.Tid__text:
switch (db.Tid()) {
case Xow_db_file_.Tid__core:
add = props.Layout_text().Tid_is_all(); // text will be in "core" if "all"
break;
case Xow_db_file_.Tid__text_solo: // EX: "en.wikipedia.org-text.xowa"
add = true; // text will be in db if solo;
break;
case Xow_db_file_.Tid__text: // EX: "en.wikipedia.org-text-ns.000.xowa"
int[] db_ns_ids = Int_ary_.Parse(db.Ns_ids(), "|"); // need to handle both "0" and "0|4"
for (int db_ns_id : db_ns_ids) {
if (db_ns_id == ns_id) {
add = true; // text will be in db if ns matches; EX: en.wikipedia.org-text-ns.014.xowa
break;
}
}
break;
}
break;
}
if (add)
rv.Add(db);
}
return (Xow_db_file[])rv.To_ary_and_clear(Xow_db_file.class);
}
public void Create_page(Xowd_page_tbl core_tbl, Xowd_text_tbl text_tbl, int page_id, int ns_id, byte[] ttl_wo_ns, boolean redirect, DateAdp modified_on, byte[] text_zip_data, int text_raw_len, int random_int, int text_db_id, int html_db_id) {
core_tbl.Insert_cmd_by_batch(page_id, ns_id, ttl_wo_ns, redirect, modified_on, text_raw_len, random_int, text_db_id, html_db_id, -1);
text_tbl.Insert_cmd_by_batch(page_id, text_zip_data);
}
private void Dbs__set_by_tid(Xow_db_file db) {
switch (db.Tid()) {
case Xow_db_file_.Tid__wiki_solo:
case Xow_db_file_.Tid__text_solo:
case Xow_db_file_.Tid__core : {db__core = db; if (props.Layout_text().Tid_is_all_or_few()) db__cat_core = db__text = db; break;}
case Xow_db_file_.Tid__text : {db__text = db; break;}
case Xow_db_file_.Tid__html_data : {db__html = db; break;}
case Xow_db_file_.Tid__wbase : {if (db__wbase == null) db__wbase = db; break;}
case Xow_db_file_.Tid__cat_core :
case Xow_db_file_.Tid__cat : {if (db__cat_core == null) db__cat_core = db; break;}
}
}
private void Dbs__add(Xow_db_file db_file) {
int db_id = db_file.Id();
hash_by_id.Add(db_id, db_file);
hash_by_tids.Add_or_new(db_file);
if (db_id >= db_id_next) // always set db_id_next to largest value in given set of dbs; EX: dbs=[0,1,10]; db_id_next should be 11
db_id_next = db_id + 1;
}
private void Dbs__add_and_save(Xow_db_file db_file) {
Dbs__add(db_file);
db__core.Tbl__db().Commit_all(this);
db_file.Info_file().Save(db_file.Tbl__cfg());
db_file.Info_session().Save(db_file.Tbl__cfg());
}
private int Get_tid_idx(Xow_db_file_hash hash, byte tid) {return hash.Count_of_tid(tid) + Int_.Base1;}
private static String Get_tid_name(int tid_idx, byte tid) {
String tid_name = Xow_db_file_.To_key(tid);
String tid_idx_str = "";
switch (tid) {
case Xow_db_file_.Tid__cat_core : break;
case Xow_db_file_.Tid__cat_link : tid_idx_str = "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break;
default : tid_idx_str = tid_idx == 1 ? "" : "-db." + Int_.To_str_pad_bgn_zero(tid_idx, 3); break;
}
return String_.Format("-{0}{1}.xowa", tid_name, tid_idx_str); // EX: en.wikipedia.org-text-001.sqlite3
}
// helper method for wikis to (a) init db_mgr; (b) load wiki.props; should probably be moved to more generic "wiki.Init_by_db()"
public static void Init_by_load(Xow_wiki wiki, Io_url core_url) {
wiki.Data__core_mgr().Init_by_load(core_url);
wiki.Props().Init_by_load(wiki.App(), wiki.Data__core_mgr().Tbl__cfg()); // load Main_page
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,66 +13,81 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*;
import gplx.core.ios.*; import gplx.dbs.*; import gplx.xowa.wikis.data.*; import gplx.xowa.wikis.data.tbls.*; import gplx.dbs.qrys.*;
import gplx.xowa.wikis.*;
public class Xodb_save_mgr_sql implements Xodb_save_mgr {
private final Xodb_mgr_sql db_mgr;
public Xodb_save_mgr_sql(Xodb_mgr_sql db_mgr) {this.db_mgr = db_mgr;}
public boolean Create_enabled() {return create_enabled;} public void Create_enabled_(boolean v) {create_enabled = v;} private boolean create_enabled;
public boolean Update_modified_on_enabled() {return update_modified_on_enabled;} public void Update_modified_on_enabled_(boolean v) {update_modified_on_enabled = v;} private boolean update_modified_on_enabled;
public int Page_id_next() {return page_id_next;} public void Page_id_next_(int v) {page_id_next = v;} private int page_id_next;
public int Data_create(Xowe_wiki wiki, Xoa_ttl ttl, byte[] text_raw) {
int ns_id = ttl.Ns().Id();
Xow_db_file db_file = db_mgr.Core_data_mgr().Db__core();
int ns_count = db_file.Tbl__ns().Select_ns_count(ns_id) + 1;
int page_id = db_file.Tbl__cfg().Select_int_or(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, -1);
if (page_id == -1) { // HACK: changed for tests; was dbs.qrys.Db_qry_sql.rdr_("SELECT (Max(page_id) + 1) AS max_page_id FROM page;")
Db_rdr rdr = db_mgr.Core_data_mgr().Tbl__page().Conn().Stmt_select(db_file.Tbl__page().Tbl_name(), String_.Ary(db_file.Tbl__page().Fld_page_id()), Dbmeta_fld_itm.Str_ary_empty).Exec_select__rls_auto();
try {
int max_page_id = -1;
while (rdr.Move_next()) {
int cur_page_id = rdr.Read_int("page_id");
if (cur_page_id > max_page_id) max_page_id = cur_page_id;
}
page_id = max_page_id + 1;
db_mgr.Core_data_mgr().Tbl__cfg().Upsert_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1);
} finally {rdr.Rls();}
}
Xow_db_mgr fsys_mgr = db_mgr.Core_data_mgr();
Xow_db_file page_text_db = fsys_mgr.Db__text();
if (page_text_db == null) page_text_db = fsys_mgr.Db__core(); // HACK: needed for create new wiki DATE:2016-10-29
Xowd_text_tbl page_text_tbl = page_text_db.Tbl__text();
byte[] text_zip = page_text_tbl.Zip(text_raw);
boolean redirect = wiki.Redirect_mgr().Is_redirect(text_raw, text_raw.length);
Xowd_page_tbl page_core_tbl = db_mgr.Core_data_mgr().Tbl__page();
page_core_tbl.Insert_bgn();
page_text_tbl.Insert_bgn();
try {
db_mgr.Core_data_mgr().Create_page(page_core_tbl, page_text_tbl, page_id, ns_id, ttl.Page_db(), redirect, Datetime_now.Get(), text_zip, text_raw.length, ns_count, page_text_db.Id(), -1);
db_file.Tbl__ns().Update_ns_count(ns_id, ns_count);
db_file.Tbl__cfg().Update_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1);
} finally {
page_core_tbl.Insert_end();
page_text_tbl.Insert_end();
}
return page_id;
}
public void Data_update(Xoae_page page, byte[] text_raw) {
boolean redirect = page.Wikie().Redirect_mgr().Is_redirect(text_raw, text_raw.length);
DateAdp modified = update_modified_on_enabled ? Datetime_now.Get() : page.Db().Page().Modified_on();
int page_id = page.Db().Page().Id();
db_mgr.Core_data_mgr().Tbl__page().Update__redirect__modified(page_id, redirect, modified);
Xowd_page_itm db_page = new Xowd_page_itm();
db_mgr.Load_mgr().Load_by_id(db_page, page_id);
Xowd_text_tbl text_tbl = db_mgr.Core_data_mgr().Dbs__get_by_id_or_fail(db_page.Text_db_id()).Tbl__text();
text_tbl.Update(page_id, text_raw);
// int html_db_id = db_page.Html_db_id();
// if (html_db_id != -1)
// db_mgr.Core_data_mgr().Tbl__page().Update__html_db_id(page_id, -1); // zap html_db_id so that next load will repopulate it
}
public void Data_rename(Xoae_page page, int trg_ns, byte[] trg_ttl) {
db_mgr.Core_data_mgr().Tbl__page().Update__ns__ttl(page.Db().Page().Id(), trg_ns, trg_ttl);
}
public void Clear() {}
}
package gplx.xowa.wikis.dbs;
import gplx.DateAdp;
import gplx.Datetime_now;
import gplx.String_;
import gplx.dbs.Db_rdr;
import gplx.dbs.Dbmeta_fld_itm;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.wikis.data.Xow_db_file;
import gplx.xowa.wikis.data.Xow_db_mgr;
import gplx.xowa.wikis.data.Xowd_cfg_key_;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
import gplx.xowa.wikis.data.tbls.Xowd_page_tbl;
import gplx.xowa.wikis.data.tbls.Xowd_text_tbl;
public class Xodb_save_mgr_sql implements Xodb_save_mgr {
private final Xodb_mgr_sql db_mgr;
public Xodb_save_mgr_sql(Xodb_mgr_sql db_mgr) {this.db_mgr = db_mgr;}
public boolean Create_enabled() {return create_enabled;} public void Create_enabled_(boolean v) {create_enabled = v;} private boolean create_enabled;
public boolean Update_modified_on_enabled() {return update_modified_on_enabled;} public void Update_modified_on_enabled_(boolean v) {update_modified_on_enabled = v;} private boolean update_modified_on_enabled;
public int Page_id_next() {return page_id_next;} public void Page_id_next_(int v) {page_id_next = v;} private int page_id_next;
public int Data_create(Xowe_wiki wiki, Xoa_ttl ttl, byte[] text_raw) {
int ns_id = ttl.Ns().Id();
Xow_db_file db_file = db_mgr.Core_data_mgr().Db__core();
int ns_count = db_file.Tbl__ns().Select_ns_count(ns_id) + 1;
int page_id = db_file.Tbl__cfg().Select_int_or(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, -1);
if (page_id == -1) { // HACK: changed for tests; was dbs.qrys.Db_qry_sql.rdr_("SELECT (Max(page_id) + 1) AS max_page_id FROM page;")
Db_rdr rdr = db_mgr.Core_data_mgr().Tbl__page().Conn().Stmt_select(db_file.Tbl__page().Tbl_name(), String_.Ary(db_file.Tbl__page().Fld_page_id()), Dbmeta_fld_itm.Str_ary_empty).Exec_select__rls_auto();
try {
int max_page_id = -1;
while (rdr.Move_next()) {
int cur_page_id = rdr.Read_int("page_id");
if (cur_page_id > max_page_id) max_page_id = cur_page_id;
}
page_id = max_page_id + 1;
db_mgr.Core_data_mgr().Tbl__cfg().Upsert_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1);
} finally {rdr.Rls();}
}
Xow_db_mgr fsys_mgr = db_mgr.Core_data_mgr();
Xow_db_file page_text_db = fsys_mgr.Db__text();
if (page_text_db == null) page_text_db = fsys_mgr.Db__core(); // HACK: needed for create new wiki DATE:2016-10-29
Xowd_text_tbl page_text_tbl = page_text_db.Tbl__text();
byte[] text_zip = page_text_tbl.Zip(text_raw);
boolean redirect = wiki.Redirect_mgr().Is_redirect(text_raw, text_raw.length);
Xowd_page_tbl page_core_tbl = db_mgr.Core_data_mgr().Tbl__page();
page_core_tbl.Insert_bgn();
page_text_tbl.Insert_bgn();
try {
db_mgr.Core_data_mgr().Create_page(page_core_tbl, page_text_tbl, page_id, ns_id, ttl.Page_db(), redirect, Datetime_now.Get(), text_zip, text_raw.length, ns_count, page_text_db.Id(), -1);
db_file.Tbl__ns().Update_ns_count(ns_id, ns_count);
db_file.Tbl__cfg().Update_int(Xowd_cfg_key_.Grp__db, Xowd_cfg_key_.Key__wiki__page__id_next, page_id + 1);
} finally {
page_core_tbl.Insert_end();
page_text_tbl.Insert_end();
}
return page_id;
}
public void Data_update(Xoae_page page, byte[] text_raw) {
boolean redirect = page.Wikie().Redirect_mgr().Is_redirect(text_raw, text_raw.length);
DateAdp modified = update_modified_on_enabled ? Datetime_now.Get() : page.Db().Page().Modified_on();
int page_id = page.Db().Page().Id();
db_mgr.Core_data_mgr().Tbl__page().Update__redirect__modified(page_id, redirect, modified);
Xowd_page_itm db_page = new Xowd_page_itm();
db_mgr.Load_mgr().Load_by_id(db_page, page_id);
Xowd_text_tbl text_tbl = db_mgr.Core_data_mgr().Dbs__get_by_id_or_fail(db_page.Text_db_id()).Tbl__text();
text_tbl.Update(page_id, text_raw);
// TOMBSTONE: do not set html_db_id to -1; editing wtxt will now save html; ISSUE#:699; DATE:2020-08-06
// if (db_page.Html_db_id() != -1)
// db_mgr.Core_data_mgr().Tbl__page().Update__html_db_id(page_id, -1); // zap html_db_id so that next load will repopulate it
}
public void Data_rename(Xoae_page page, int trg_ns, byte[] trg_ttl) {
db_mgr.Core_data_mgr().Tbl__page().Update__ns__ttl(page.Db().Page().Id(), trg_ns, trg_ttl);
}
public void Clear() {}
}

@ -1,145 +1,146 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.pages;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Err_;
import gplx.Gfo_usr_dlg_;
import gplx.core.net.qargs.Gfo_qarg_itm;
import gplx.core.net.qargs.Gfo_qarg_mgr;
import gplx.xowa.Xoa_app;
import gplx.xowa.Xoa_app_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoa_url_;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.Xowe_wiki_;
import gplx.xowa.addons.wikis.pages.syncs.core.Xosync_read_mgr;
import gplx.xowa.guis.views.Xog_tab_itm;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
public class Xowe_page_mgr {
private final Xowe_wiki wiki;
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private final Gfo_qarg_mgr tmp_qarg_mgr = new Gfo_qarg_mgr();
public Xowe_page_mgr(Xowe_wiki wiki) {this.wiki = wiki;}
public Xosync_read_mgr Sync_mgr() {return read_mgr;} private final Xosync_read_mgr read_mgr = new Xosync_read_mgr();
public void Init_by_wiki(Xowe_wiki wiki) {
read_mgr.Init_by_wiki(wiki);
}
public Xoae_page Load_page(Xoa_url url, Xoa_ttl ttl, Xog_tab_itm tab) { // NOTE: called by GUI and HTTP_SERVER; not called by MASS_PARSE
Xoa_app_.Usr_dlg().Log_many("", "", "page.load: url=~{0}", url.To_str());
Wait_for_popups(wiki.App());
Xowe_wiki_.Rls_mem_if_needed(wiki);
// handle curid query_arg; EX:en.wikipedia.org/wiki/?curid=303 DATE:2017-02-15
Gfo_qarg_itm[] qarg_ary = url.Qargs_ary();
// if qargs exist...
if (qarg_ary.length > 0) {
try {
tmp_qarg_mgr.Init(qarg_ary);
byte[] curid_bry = tmp_qarg_mgr.Read_bry_or(Xoa_url_.Qarg__curid, null);
// if "curid" qarg exists....
if (curid_bry != null) {
int curid = Bry_.To_int_or(curid_bry, -1);
Xowd_page_itm tmp_page = wiki.Data__core_mgr().Db__core().Tbl__page().Select_by_id_or_null(curid);
// if curid exists in page tbl...
if (tmp_page != null) {
ttl = wiki.Ttl_parse(tmp_page.Ns_id(), tmp_page.Ttl_page_db());
// handle "home/wiki/?curid=123"; XO automatically changes to "home/wiki/Main_Page?curid=123"; change back to "home/wiki/?curid=123"
if (url.Page_is_main()) {
url.Page_bry_(Bry_.Empty);
}
}
}
} catch (Exception exc) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to handle cur_id; url=~{0} err=~{1}", url.Raw(), Err_.Message_gplx_log(exc));
}
}
// load page meta; wait_for_popups
Xoae_page page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false);
ttl = page.Ttl(); // note that Load_page_and_parse can redirect ttl; EX: Special:Random -> A; DATE:2017-01-05
Wait_for_popups(wiki.App());
// auto-update
Xoa_ttl redirect_ttl = read_mgr.Auto_update(wiki, page, ttl);
if (redirect_ttl != null) {
// page-sync occurred; update ttl to handle any redirection; DATE:2017-05-07
ttl = redirect_ttl;
// reload metadata, needed to pick up Html_db_id; DATE:2017-03-13
page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false);
}
// load from html_db
boolean from_html_db = page.Db().Page().Html_db_id() != -1;
boolean read_from_html_db_preferred = wiki.Html__hdump_mgr().Load_mgr().Read_preferred();
boolean isCategoryPage = ttl.Ns().Id_is_ctg();
if (from_html_db) {
if (read_from_html_db_preferred) {
wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, !isCategoryPage); // NOTE: if loading for html_db, do not build page_box; will be built below; ISSUE#:722; DATE:2020-05-17
int html_len = Bry_.Len(page.Db().Html().Html_bry());
from_html_db = html_len > 0; // NOTE: archive.org has some wtxt_dbs which included page|html_db_id without actual html_dbs; DATE:2016-06-22
Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded html; page=~{0} html_len=~{1}", ttl.Full_db(), html_len);
}
else
from_html_db = false;
}
// load from wtxt_db; occurs if (a) no html_db_id; (b) option says to use wtxt db; (c) html_db_id exists, but no html_db;
if (!from_html_db) {
wiki.Parser_mgr().Parse(page, false);
// load from html_db if no wtxt found and option just marked as not read_preferred
if ( Bry_.Len_eq_0(page.Db().Text().Text_bry()) // no wtxt found
&& !ttl.Ns().Id_is_special() // skip special
&& !read_from_html_db_preferred // read preferred not marked
) {
wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, true);
from_html_db = Bry_.Len_gt_0(page.Db().Html().Html_bry());
}
else {
Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded wikitext; page=~{0} wikitext_len=~{1}", ttl.Full_db(), page.Db().Text().Text_bry().length);
}
}
page.Html_data().Hdump_exists_(from_html_db);
// if [[Category]], generate catlinks (subc; page; file)
if (isCategoryPage) {
wiki.Ctg__catpage_mgr().Write_catpage(tmp_bfr, page);
if (from_html_db) {
wiki.Ctg__pagebox_wtr().Write_pagebox(tmp_bfr, page);
page.Db().Html().Html_bry_(Bry_.Add(page.Db().Html().Html_bry(), tmp_bfr.To_bry_and_clear()));
}
else {
page.Html_data().Catpage_data_(tmp_bfr.To_bry_and_clear());
}
}
return page;
}
private static void Wait_for_popups(Xoa_app app) {// HACK: wait for popups to finish, else thread errors due to popups and loader mutating cached items
if (app.Mode().Tid_is_http()) return;
int wait_count = 0;
while (gplx.xowa.htmls.modules.popups.Xow_popup_mgr.Running() && ++wait_count < 100)
gplx.core.threads.Thread_adp_.Sleep(10);
}
}
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.pages;
import gplx.Bry_;
import gplx.Bry_bfr;
import gplx.Bry_bfr_;
import gplx.Err_;
import gplx.Gfo_usr_dlg_;
import gplx.core.net.qargs.Gfo_qarg_itm;
import gplx.core.net.qargs.Gfo_qarg_mgr;
import gplx.xowa.Xoa_app;
import gplx.xowa.Xoa_app_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xoa_url;
import gplx.xowa.Xoa_url_;
import gplx.xowa.Xoae_page;
import gplx.xowa.Xowe_wiki;
import gplx.xowa.Xowe_wiki_;
import gplx.xowa.addons.wikis.pages.syncs.core.Xosync_read_mgr;
import gplx.xowa.guis.views.Xog_tab_itm;
import gplx.xowa.wikis.data.tbls.Xowd_page_itm;
import gplx.xowa.wikis.pages.dbs.Xopg_db_page;
public class Xowe_page_mgr {
private final Xowe_wiki wiki;
private final Bry_bfr tmp_bfr = Bry_bfr_.New();
private final Gfo_qarg_mgr tmp_qarg_mgr = new Gfo_qarg_mgr();
public Xowe_page_mgr(Xowe_wiki wiki) {this.wiki = wiki;}
public Xosync_read_mgr Sync_mgr() {return read_mgr;} private final Xosync_read_mgr read_mgr = new Xosync_read_mgr();
public void Init_by_wiki(Xowe_wiki wiki) {
read_mgr.Init_by_wiki(wiki);
}
public Xoae_page Load_page(Xoa_url url, Xoa_ttl ttl, Xog_tab_itm tab) { // NOTE: called by GUI and HTTP_SERVER; not called by MASS_PARSE
Xoa_app_.Usr_dlg().Log_many("", "", "page.load: url=~{0}", url.To_str());
Wait_for_popups(wiki.App());
Xowe_wiki_.Rls_mem_if_needed(wiki);
// handle curid query_arg; EX:en.wikipedia.org/wiki/?curid=303 DATE:2017-02-15
Gfo_qarg_itm[] qarg_ary = url.Qargs_ary();
// if qargs exist...
if (qarg_ary.length > 0) {
try {
tmp_qarg_mgr.Init(qarg_ary);
byte[] curid_bry = tmp_qarg_mgr.Read_bry_or(Xoa_url_.Qarg__curid, null);
// if "curid" qarg exists....
if (curid_bry != null) {
int curid = Bry_.To_int_or(curid_bry, -1);
Xowd_page_itm tmp_page = wiki.Data__core_mgr().Db__core().Tbl__page().Select_by_id_or_null(curid);
// if curid exists in page tbl...
if (tmp_page != null) {
ttl = wiki.Ttl_parse(tmp_page.Ns_id(), tmp_page.Ttl_page_db());
// handle "home/wiki/?curid=123"; XO automatically changes to "home/wiki/Main_Page?curid=123"; change back to "home/wiki/?curid=123"
if (url.Page_is_main()) {
url.Page_bry_(Bry_.Empty);
}
}
}
} catch (Exception exc) {
Gfo_usr_dlg_.Instance.Warn_many("", "", "failed to handle cur_id; url=~{0} err=~{1}", url.Raw(), Err_.Message_gplx_log(exc));
}
}
// load page meta; wait_for_popups
Xoae_page page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false);
ttl = page.Ttl(); // note that Load_page_and_parse can redirect ttl; EX: Special:Random -> A; DATE:2017-01-05
Wait_for_popups(wiki.App());
// auto-update
Xoa_ttl redirect_ttl = read_mgr.Auto_update(wiki, page, ttl);
if (redirect_ttl != null) {
// page-sync occurred; update ttl to handle any redirection; DATE:2017-05-07
ttl = redirect_ttl;
// reload metadata, needed to pick up Html_db_id; DATE:2017-03-13
page = wiki.Data_mgr().Load_page_and_parse(url, ttl, wiki.Lang(), tab, false);
}
// load from html_db
boolean from_html_db = page.Db().Page().Html_db_id() != Xopg_db_page.HTML_DB_ID_NULL;
boolean read_from_html_db_preferred = wiki.Html__hdump_mgr().Load_mgr().Read_preferred();
boolean isCategoryPage = ttl.Ns().Id_is_ctg();
if (from_html_db) {
if (read_from_html_db_preferred) {
wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, !isCategoryPage); // NOTE: if loading for html_db, do not build page_box; will be built below; ISSUE#:722; DATE:2020-05-17
int html_len = Bry_.Len(page.Db().Html().Html_bry());
from_html_db = html_len > 0; // NOTE: archive.org has some wtxt_dbs which included page|html_db_id without actual html_dbs; DATE:2016-06-22
Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded html; page=~{0} html_len=~{1}", ttl.Full_db(), html_len);
}
else
from_html_db = false;
}
// load from wtxt_db; occurs if (a) no html_db_id; (b) option says to use wtxt db; (c) html_db_id exists, but no html_db;
if (!from_html_db) {
wiki.Parser_mgr().Parse(page, false);
// load from html_db if no wtxt found and option just marked as not read_preferred
if ( Bry_.Len_eq_0(page.Db().Text().Text_bry()) // no wtxt found
&& !ttl.Ns().Id_is_special() // skip special
&& !read_from_html_db_preferred // read preferred not marked
) {
wiki.Html__hdump_mgr().Load_mgr().Load_by_xowe(page, true);
from_html_db = Bry_.Len_gt_0(page.Db().Html().Html_bry());
}
else {
Gfo_usr_dlg_.Instance.Log_many("", "", "page_load: loaded wikitext; page=~{0} wikitext_len=~{1}", ttl.Full_db(), page.Db().Text().Text_bry().length);
}
}
page.Html_data().Hdump_exists_(from_html_db);
// if [[Category]], generate catlinks (subc; page; file)
if (isCategoryPage) {
wiki.Ctg__catpage_mgr().Write_catpage(tmp_bfr, page);
if (from_html_db) {
wiki.Ctg__pagebox_wtr().Write_pagebox(tmp_bfr, page);
page.Db().Html().Html_bry_(Bry_.Add(page.Db().Html().Html_bry(), tmp_bfr.To_bry_and_clear()));
}
else {
page.Html_data().Catpage_data_(tmp_bfr.To_bry_and_clear());
}
}
return page;
}
private static void Wait_for_popups(Xoa_app app) {// HACK: wait for popups to finish, else thread errors due to popups and loader mutating cached items
if (app.Mode().Tid_is_http()) return;
int wait_count = 0;
while (gplx.xowa.htmls.modules.popups.Xow_popup_mgr.Running() && ++wait_count < 100)
gplx.core.threads.Thread_adp_.Sleep(10);
}
}

@ -1,6 +1,6 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
Copyright (C) 2012-2020 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
@ -13,54 +13,65 @@ The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.wikis.pages.dbs; import gplx.*; import gplx.xowa.*; import gplx.xowa.wikis.*; import gplx.xowa.wikis.pages.*;
import gplx.xowa.wikis.nss.*;
public class Xopg_db_page {
public Xopg_db_page() {this.Clear();}
// from page table
public boolean Exists() {return exists;} private boolean exists;
public boolean Exists_n() {return !exists;}
public int Id() {return id;} private int id;
public int Ns_id() {return ns_id;} private int ns_id;
public byte[] Ttl_bry() {return ttl_bry;} private byte[] ttl_bry;
public DateAdp Modified_on() {return modified_on;} private DateAdp modified_on;
public int Text_len() {return text_len;} private int text_len;
public int Text_db_id() {return text_db_id;} private int text_db_id;
public int Html_db_id() {return html_db_id;} private int html_db_id;
public int Redirect_to_id() {return redirect_to_id;} private int redirect_to_id;
public int Score() {return score;} private int score;
public void Exists_y_() {this.Exists_(Bool_.Y);}
public void Exists_n_() {this.Exists_(Bool_.N);}
public void Exists_(boolean v) {this.exists = v;}
public Xopg_db_page Id_(int v) {this.id = v; return this;}
public Xopg_db_page Score_(int v) {this.score = v; return this;}
public Xopg_db_page Modified_on_(DateAdp v) {this.modified_on = v; return this;}
public Xopg_db_page Html_db_id_(int v) {this.html_db_id = v; return this;}
// wiki-related
public Xow_ns Ns() {return ns;} private Xow_ns ns;
public Xoa_ttl Ttl() {return ttl;} private Xoa_ttl ttl;
// init methods
public Xopg_db_page Init_by_db(int id, int ns_id, byte[] ttl_bry, DateAdp modified_on, int text_len, int text_db_id, int html_db_id, int redirect_to_id, int score) {
this.id = id; this.ns_id = ns_id; this.ttl_bry = ttl_bry; this.modified_on = modified_on;
this.text_len = text_len; this.text_db_id = text_db_id; this.html_db_id = html_db_id; this.redirect_to_id = redirect_to_id; this.score = score;
this.ns = null; this.ttl = null;
return this;
}
public Xopg_db_page Init_by_wiki(Xow_wiki wiki) {
this.ns = wiki.Ns_mgr().Ids_get_or_null(ns_id);
this.ttl = wiki.Ttl_parse(ns_id, ttl_bry);
return this;
}
public void Init_by_mp(int id, int score) {
this.id = id;
this.score = score;
}
public void Clear() {
this.exists = true;
this.modified_on = DateAdp_.MinValue; // NOTE: must set to MinValue else some tests will fail
this.html_db_id = -1; // NOTE: must set to -1 b/c code checks for -1 to indicate no html; DATE:2016-07-14
}
}
package gplx.xowa.wikis.pages.dbs;
import gplx.Bool_;
import gplx.DateAdp;
import gplx.DateAdp_;
import gplx.xowa.Xoa_ttl;
import gplx.xowa.Xow_wiki;
import gplx.xowa.wikis.nss.Xow_ns;
public class Xopg_db_page {
public Xopg_db_page() {this.Clear();}
// from page table
public boolean Exists() {return exists;} private boolean exists;
public boolean Exists_n() {return !exists;}
public int Id() {return id;} private int id;
public int Ns_id() {return ns_id;} private int ns_id;
public byte[] Ttl_bry() {return ttl_bry;} private byte[] ttl_bry;
public DateAdp Modified_on() {return modified_on;} private DateAdp modified_on;
public int Text_len() {return text_len;} private int text_len;
public int Text_db_id() {return text_db_id;} private int text_db_id;
public int Html_db_id() {return html_db_id;} private int html_db_id;
public int Redirect_to_id() {return redirect_to_id;} private int redirect_to_id;
public int Score() {return score;} private int score;
public void Exists_y_() {this.Exists_(Bool_.Y);}
public void Exists_n_() {this.Exists_(Bool_.N);}
public void Exists_(boolean v) {this.exists = v;}
public Xopg_db_page Id_(int v) {this.id = v; return this;}
public Xopg_db_page Score_(int v) {this.score = v; return this;}
public Xopg_db_page Modified_on_(DateAdp v) {this.modified_on = v; return this;}
public Xopg_db_page Html_db_id_(int v) {this.html_db_id = v; return this;}
// wiki-related
public Xow_ns Ns() {return ns;} private Xow_ns ns;
public Xoa_ttl Ttl() {return ttl;} private Xoa_ttl ttl;
// init methods
public Xopg_db_page Init_by_db(int id, int ns_id, byte[] ttl_bry, DateAdp modified_on, int text_len, int text_db_id, int html_db_id, int redirect_to_id, int score) {
this.id = id; this.ns_id = ns_id; this.ttl_bry = ttl_bry; this.modified_on = modified_on;
this.text_len = text_len; this.text_db_id = text_db_id; this.html_db_id = html_db_id; this.redirect_to_id = redirect_to_id; this.score = score;
this.ns = null; this.ttl = null;
return this;
}
public Xopg_db_page Init_by_wiki(Xow_wiki wiki) {
this.ns = wiki.Ns_mgr().Ids_get_or_null(ns_id);
this.ttl = wiki.Ttl_parse(ns_id, ttl_bry);
return this;
}
public void Init_by_mp(int id, int score) {
this.id = id;
this.score = score;
}
public void Clear() {
this.exists = true;
this.modified_on = DateAdp_.MinValue; // NOTE: must set to MinValue else some tests will fail
// NOTE: must set to -1 b/c code checks for -1 to indicate no html; DATE:2016-07-14;
// NOTE: this should probably be removed, but would need to change all the checks; DATE:2020-08-06
this.html_db_id = Xopg_db_page.HTML_DB_ID_NULL;
}
public static final int HTML_DB_ID_NULL = -1;
}

Loading…
Cancel
Save