Skip to content
This repository was archived by the owner on Nov 16, 2019. It is now read-only.

Commit fbd1379

Browse files
committed
fix(Options): fix memory leak due to detached DOM tree
1 parent fff0bd2 commit fbd1379

File tree

13 files changed

+246
-155
lines changed

13 files changed

+246
-155
lines changed

src/cache.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ define('cache', function (require, _exports, module) {
3030
var BaseView = cache.BaseView = Backbone.View.extend({
3131
initialize: function () {
3232
var _this = this;
33+
_this.subviews = {data: {}};
34+
_this.childViews = [];
3335
if (_this.templateUrl) {
3436
_this.__gotTemplate = cache.get(_this.templateUrl)
3537
.then(function (fn) {
@@ -39,6 +41,21 @@ define('cache', function (require, _exports, module) {
3941
_.bindAll(_this, 'render', 'postrender');
4042
_this.render();
4143
},
44+
clear: function () {
45+
var _this = this;
46+
if (_this.childViews.length) {
47+
_this.childViews.forEach(function (view) {
48+
view.remove();
49+
});
50+
_this.childViews = [];
51+
}
52+
},
53+
remove: function () {
54+
var _this = this;
55+
_this.clear();
56+
_this.undelegateEvents();
57+
Backbone.View.prototype.remove.call(_this);
58+
},
4259
_render: function () {
4360
this.$el.html(this.templateFn());
4461
},
@@ -54,6 +71,27 @@ define('cache', function (require, _exports, module) {
5471
node.innerHTML = _.i18n(node.dataset.i18n);
5572
});
5673
},
74+
loadSubview: function (name, factory, selector) {
75+
var _this = this;
76+
var view;
77+
var subviews = _this.subviews;
78+
view = subviews.data[name];
79+
if (!view) {
80+
view = factory();
81+
}
82+
var current = subviews.current;
83+
if (name !== current) {
84+
var currentView = subviews.data[current];
85+
if (currentView) {
86+
currentView.remove();
87+
subviews.data[current] = null;
88+
}
89+
}
90+
subviews.data[subviews.current = name] = view;
91+
var $el = selector ? _this.$(selector) : _this.$el;
92+
$el.html(view.render().el);
93+
return view;
94+
},
5795
getValue: function (target) {
5896
var key = target.dataset.id;
5997
var value;
@@ -78,6 +116,30 @@ define('cache', function (require, _exports, module) {
78116

79117
BaseView.prototype.postrender.call(window);
80118

119+
cache.BaseRouter = Backbone.Router.extend({
120+
initialize: function (selector) {
121+
var _this = this;
122+
_this.views = {data: {}};
123+
_this.$root = $(selector);
124+
},
125+
loadView: function (name, factory) {
126+
var _this = this;
127+
var views = _this.views;
128+
var view = views.data[name];
129+
if (!view) view = views.data[name] = factory();
130+
if (name !== views.current) {
131+
var currentView = views.data[views.current];
132+
if (currentView) {
133+
currentView.remove();
134+
views.data[views.current] = null;
135+
}
136+
views.data[views.current = name] = view;
137+
}
138+
_this.$root.html(view.el);
139+
return view;
140+
},
141+
});
142+
81143
!function () {
82144
var xhr = new XMLHttpRequest;
83145
xhr.open('GET', '/images/sprite.svg', true);

src/options/app.js

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
11
define('app', function (require, exports, _module) {
2-
var models = require('models');
32
var MainView = require('views/Main');
43
var ConfirmView = require('views/Confirm');
5-
var EditView = require('views/Edit');
6-
7-
var scriptList = exports.scriptList = new models.ScriptList;
8-
_.bg._.messenger.connect(window, function (res) {
9-
if (res.cmd === 'add') {
10-
res.data.message = '';
11-
scriptList.push(res.data);
12-
} else if (res.data) {
13-
var model = scriptList.get(res.data.id);
14-
if (model) model.set(res.data);
15-
}
16-
});
4+
var models = require('models');
5+
var cache = require('cache');
176

18-
var App = Backbone.Router.extend({
7+
var App = cache.BaseRouter.extend({
198
routes: {
209
'': 'renderMain',
2110
'main/:tab': 'renderMain',
2211
'confirm/:url': 'renderConfirm',
2312
'confirm/:url/:from': 'renderConfirm',
2413
},
2514
renderMain: function (tab) {
26-
this.view = new MainView(tab);
27-
},
28-
renderConfirm: function (url, _from) {
29-
this.view = new ConfirmView(url, _from);
15+
this.loadView('main', function () {
16+
initMain();
17+
return new MainView;
18+
}).loadTab(tab);
3019
},
31-
renderEdit: function (id) {
32-
this.view = new EditView(id);
20+
renderConfirm: function (url, referer) {
21+
this.loadView('confirm', function () {
22+
return new ConfirmView;
23+
}).initData(url, referer);
3324
},
3425
});
35-
var app = new App;
36-
if (!Backbone.history.start())
37-
app.navigate('', {trigger: true, replace: true});
26+
var app = new App('#app');
27+
Backbone.history.start() || app.navigate('', {trigger: true, replace: true});
28+
29+
function initMain() {
30+
var scriptList = exports.scriptList = new models.ScriptList;
31+
_.bg._.messenger.connect(window, function (res) {
32+
if (res.cmd === 'add') {
33+
res.data.message = '';
34+
scriptList.push(res.data);
35+
} else if (res.data) {
36+
var model = scriptList.get(res.data.id);
37+
if (model) model.set(res.data);
38+
}
39+
});
40+
}
3841
});

src/options/style.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ aside img {
9595
border-right: 1px solid darkgray;
9696
overflow-y: hidden;
9797
}
98-
#tab > header {
98+
.content > header {
9999
height: 30px;
100100
line-height: 30px;
101101
padding: 0 .5rem;
@@ -144,6 +144,9 @@ aside img {
144144
padding: 20px;
145145
overflow-y: auto;
146146
}
147+
.no-pad {
148+
padding: 0;
149+
}
147150
fieldset.title {
148151
margin-top: 20px;
149152
padding: 10px;

src/options/templates/confirm.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<button id=btnClose data-i18n=buttonClose></button>
99
</div>
1010
<h1><span data-i18n=labelInstall></span> - <span data-i18n=extName></span></h1>
11-
<div id=url class=ellipsis title="<%- it.url %>"><%- it.url %></div>
11+
<div id=url class=ellipsis></div>
1212
<div id=msg class=ellipsis></div>
1313
</div>
1414
<div class=frame-body>

src/options/templates/main.html

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
<div class="main">
2-
<aside>
3-
<img src="/images/icon128.png">
4-
<h2 data-i18n=extName></h2>
5-
<div class="line">2013-2016</div>
6-
<hr>
7-
<div class=sidemenu>
8-
<a href="#main/installed" <%= it.tab == 'main' ? 'class="active"' : '' %> data-i18n=sideMenuInstalled></a>
9-
<a href="#main/settings" <%= it.tab == 'settings' ? 'class="active"' : '' %> data-i18n=sideMenuSettings></a>
10-
<a href="#main/about" <%= it.tab == 'about' ? 'class="active"' : '' %> data-i18n=sideMenuAbout></a>
11-
</div>
12-
</aside>
13-
<div id="tab"></div>
14-
</div>
1+
<aside>
2+
<img src="/images/icon128.png">
3+
<h2 data-i18n=extName></h2>
4+
<div class="line">2013-2016</div>
5+
<hr>
6+
<div class=sidemenu>
7+
<a href="#main/installed" <%= it.tab == 'main' ? 'class="active"' : '' %> data-i18n=sideMenuInstalled></a>
8+
<a href="#main/settings" <%= it.tab == 'settings' ? 'class="active"' : '' %> data-i18n=sideMenuSettings></a>
9+
<a href="#main/about" <%= it.tab == 'about' ? 'class="active"' : '' %> data-i18n=sideMenuAbout></a>
10+
</div>
11+
</aside>
12+
<div id="tab"></div>
Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
1-
<div class="content">
2-
<h1>
3-
<span data-i18n=labelAbout></span>
4-
<small>v<%= it.version %></small>
5-
</h1>
6-
<div class=line data-i18n=extDescription></div>
7-
<div class=line>
8-
<label data-i18n=labelRelated></label>
9-
<span data-i18n=anchorSupportPage></span> |
10-
<a href=https://gerald.top/~donate target=_blank data-i18n=labelDonate></a> |
11-
<a href=https://github.com/violentmonkey/violentmonkey-oex/issues target=_blank data-i18n=labelFeedback></a>
12-
</div>
13-
<div class=line>
14-
<label data-i18n=labelAuthor></label>
15-
<span data-i18n=anchorAuthor></span>
16-
</div>
17-
<div class=line>
18-
<label data-i18n=labelTranslator></label>
19-
<span data-i18n=anchorTranslator></span>
20-
</div>
21-
<div class=line>
22-
<label data-i18n=labelCurrentLang></label>
23-
<span id="currentLang"><%= navigator.language %></span> |
24-
<a href=https://violentmonkey.github.io/localization.html#oex target=_blank>
25-
Help with translation
26-
</a>
27-
</div>
1+
<h1>
2+
<span data-i18n=labelAbout></span>
3+
<small>v<%= it.version %></small>
4+
</h1>
5+
<div class=line data-i18n=extDescription></div>
6+
<div class=line>
7+
<label data-i18n=labelRelated></label>
8+
<span data-i18n=anchorSupportPage></span> |
9+
<a href=https://gerald.top/~donate target=_blank data-i18n=labelDonate></a> |
10+
<a href=https://github.com/violentmonkey/violentmonkey-oex/issues target=_blank data-i18n=labelFeedback></a>
11+
</div>
12+
<div class=line>
13+
<label data-i18n=labelAuthor></label>
14+
<span data-i18n=anchorAuthor></span>
15+
</div>
16+
<div class=line>
17+
<label data-i18n=labelTranslator></label>
18+
<span data-i18n=anchorTranslator></span>
19+
</div>
20+
<div class=line>
21+
<label data-i18n=labelCurrentLang></label>
22+
<span id="currentLang"><%= navigator.language %></span> |
23+
<a href=https://violentmonkey.github.io/localization.html#oex target=_blank>
24+
Help with translation
25+
</a>
2826
</div>
Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
1-
<div class="content">
2-
<h1 data-i18n=labelSettings></h1>
3-
<label class="line">
4-
<input id=cUpdate type=checkbox data-check=autoUpdate <%= it.autoUpdate ? 'checked' : '' %>>
5-
<span data-i18n=labelAutoUpdate></span>
1+
<h1 data-i18n=labelSettings></h1>
2+
<label class="line">
3+
<input id=cUpdate type=checkbox data-check=autoUpdate <%= it.autoUpdate ? 'checked' : '' %>>
4+
<span data-i18n=labelAutoUpdate></span>
5+
</label>
6+
<fieldset class=title>
7+
<legend data-i18n=labelDataImport></legend>
8+
<div id="groupImport">
9+
<button id=bImport data-i18n=buttonImportData></button>
10+
<input type=file id="bImportHelper">
11+
</div>
12+
<button id=bVacuum data-i18n=buttonVacuum title="<%- _.i18n('hintVacuum') %>"></button>
13+
</fieldset>
14+
<fieldset class=title>
15+
<legend data-i18n=labelDataExport></legend>
16+
<b data-i18n=labelScriptsToExport></b>
17+
<label>
18+
<input id=cbValues type=checkbox data-check=exportValues <%= it.exportValues ? 'checked' : '' %>>
19+
<span data-i18n=labelExportScriptData></span>
620
</label>
7-
<fieldset class=title>
8-
<legend data-i18n=labelDataImport></legend>
9-
<div id="groupImport">
10-
<button id=bImport data-i18n=buttonImportData></button>
11-
<input type=file id="bImportHelper">
12-
</div>
13-
<button id=bVacuum data-i18n=buttonVacuum title="<%- _.i18n('hintVacuum') %>"></button>
14-
</fieldset>
15-
<fieldset class=title>
16-
<legend data-i18n=labelDataExport></legend>
17-
<b data-i18n=labelScriptsToExport></b>
18-
<label>
19-
<input id=cbValues type=checkbox data-check=exportValues <%= it.exportValues ? 'checked' : '' %>>
20-
<span data-i18n=labelExportScriptData></span>
21-
</label>
22-
<div class=export-list multiple></div>
23-
<button id=bSelect data-i18n=buttonAllNone></button>
24-
<button id=bExport data-i18n=buttonExportData></button>
25-
</fieldset>
26-
</div>
21+
<div class=export-list></div>
22+
<button id=bSelect data-i18n=buttonAllNone></button>
23+
<button id=bExport data-i18n=buttonExportData></button>
24+
</fieldset>

0 commit comments

Comments
 (0)