xc_html_generator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/html/page.html.erb +285 -0
- data/lib/xc_html_generator.rb +125 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 25460904a9b2cb299009f1328895c4510cb5926e293e1cae9d47cbc569c9aa16
|
4
|
+
data.tar.gz: 25f2bc9ab1020212c535b02b7eb27d6e2c07fc9a1b4a4c0d4942169a346aadcd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 10f784b665bd07a0e374ada0727b3798c11238cb2ba7449c9050ca76621e3010deae41ddd83f1480d535755b7f9aa76f091246335ebe99e9d2d58f8c05e9f767
|
7
|
+
data.tar.gz: 4572bc001b4da3654baf30f318467472f42ae97436e0f0966645654d8f19c859a1655677c84615f347ff7034de1ef0956062a51d4055b357e91fa2111910a6cc
|
@@ -0,0 +1,285 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>fastlane/snapshot</title>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<style type="text/css">
|
7
|
+
* {
|
8
|
+
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
|
9
|
+
font-weight: 300;
|
10
|
+
}
|
11
|
+
#sortMenu {
|
12
|
+
overflow: hidden;
|
13
|
+
border: 1px solid #ccc;
|
14
|
+
background-color: #f1f1f1;
|
15
|
+
display: none;
|
16
|
+
}
|
17
|
+
#sortMenu button {
|
18
|
+
background-color: inherit;
|
19
|
+
float: left;
|
20
|
+
border: none;
|
21
|
+
outline: none;
|
22
|
+
cursor: pointer;
|
23
|
+
padding: 14px 16px;
|
24
|
+
font-size: 17px;
|
25
|
+
}
|
26
|
+
#sortMenu button:hover {
|
27
|
+
background-color: #ddd;
|
28
|
+
}
|
29
|
+
#sortMenu button.active {
|
30
|
+
background-color: #ccc;
|
31
|
+
}
|
32
|
+
.deviceName {
|
33
|
+
display: block;
|
34
|
+
font-size: 30px;
|
35
|
+
padding-bottom: 24px;
|
36
|
+
padding-top: 45px;
|
37
|
+
}
|
38
|
+
.screenshot {
|
39
|
+
cursor: pointer;
|
40
|
+
border: 1px #EEE solid;
|
41
|
+
z-index: 0;
|
42
|
+
}
|
43
|
+
.caption {
|
44
|
+
font-size: 24px;
|
45
|
+
padding-bottom: 24px;
|
46
|
+
padding-top: 30px;
|
47
|
+
}
|
48
|
+
h1, h2 {
|
49
|
+
font-weight: bold;
|
50
|
+
}
|
51
|
+
th {
|
52
|
+
text-align: left;
|
53
|
+
}
|
54
|
+
td {
|
55
|
+
text-align: center;
|
56
|
+
min-width: 200px;
|
57
|
+
}
|
58
|
+
#overlay {
|
59
|
+
position:fixed;
|
60
|
+
top:0;
|
61
|
+
left:0;
|
62
|
+
background:rgba(0,0,0,0.8);
|
63
|
+
z-index:5;
|
64
|
+
width:100%;
|
65
|
+
height:100%;
|
66
|
+
display:none;
|
67
|
+
cursor: zoom-out;
|
68
|
+
text-align: center;
|
69
|
+
}
|
70
|
+
#imageDisplay {
|
71
|
+
height: auto;
|
72
|
+
width: auto;
|
73
|
+
z-index: 10;
|
74
|
+
cursor: pointer;
|
75
|
+
}
|
76
|
+
#imageInfo {
|
77
|
+
background: none repeat scroll 0 0 rgba(0, 0, 0, 0.2);
|
78
|
+
border-radius: 5px;
|
79
|
+
color: white;
|
80
|
+
margin: 20px;
|
81
|
+
padding: 10px;
|
82
|
+
position: absolute;
|
83
|
+
right: 0;
|
84
|
+
top: 0;
|
85
|
+
width: 250px;
|
86
|
+
z-index: -1;
|
87
|
+
}
|
88
|
+
#imageInfo:hover {
|
89
|
+
z-index: 20;
|
90
|
+
}
|
91
|
+
</style>
|
92
|
+
</head>
|
93
|
+
<body>
|
94
|
+
<div id="sortMenu">
|
95
|
+
<button id="defaultTab" class="tabLink" onclick="openTab(event, 'byLanguage')">By Language</button>
|
96
|
+
<button class="tabLink" onclick="openTab(event, 'byScreen')">By Screen</button>
|
97
|
+
</div>
|
98
|
+
<div id="byLanguage" class="tabContent"><h1 class="tabTitle">By Language:</h1><% image_counter = 0 %><% @data_by_language.each do |language, content| %>
|
99
|
+
<h2 id="<%= language %>"><%= language %></h2>
|
100
|
+
<hr>
|
101
|
+
<table><% content.each do |device_name, screens| %>
|
102
|
+
<tr>
|
103
|
+
<th colspan="<%= screens.count %>">
|
104
|
+
<a id="<%= language %>-<%= device_name %>" class="deviceName" href="#<%= language %>-<%= device_name %>"><%= device_name %></a>
|
105
|
+
</th>
|
106
|
+
</tr>
|
107
|
+
<tr><% screens.each do |screen_path| %><% next if screen_path.include?"_framed.png" %>
|
108
|
+
<td><% image_counter += 1 %>
|
109
|
+
<a href="<%= screen_path %>" target="_blank" class="screenshotLink">
|
110
|
+
<img class="screenshot" src="<%= screen_path %>" style="width: 100%;" alt="<%= language %> <%= device_name %>" data-tab="1" data-counter="<%= image_counter %>">
|
111
|
+
</a>
|
112
|
+
</td><% end %>
|
113
|
+
</tr><% end %>
|
114
|
+
</table><% end %>
|
115
|
+
</div>
|
116
|
+
<div id="byScreen" class="tabContent"><h1 class="tabTitle">By Screen:</h1><% image_counter = 0 %><% @data_by_screen.each do |screen, content| %>
|
117
|
+
<h2 id="<%= screen %>" class="screen"><%= screen %></h2>
|
118
|
+
<hr>
|
119
|
+
<table><% content.each do |device_name, screens| %>
|
120
|
+
<tr>
|
121
|
+
<th colspan="<%= screens.count %>">
|
122
|
+
<a id="<%= screen %>-<%= device_name %>" class="deviceName" href="#<%= screen %>-<%= device_name %>"><%= device_name %></a>
|
123
|
+
</th>
|
124
|
+
</tr>
|
125
|
+
<tr><% screens.each do |language, screen_path| %><% next if screen_path.include?"_framed.png" %>
|
126
|
+
<td><% image_counter += 1 %>
|
127
|
+
<a href="<%= screen_path %>" target="_blank" class="screenshotLink">
|
128
|
+
<img class="screenshot" src="<%= screen_path %>" style="width: 100%;" alt="<%= language %> <%= device_name %>" data-tab="2" data-counter="<%= image_counter %>">
|
129
|
+
</a>
|
130
|
+
<div class="caption"><%= language %></div>
|
131
|
+
</td><% end %>
|
132
|
+
</tr><% end %>
|
133
|
+
</table><% end %>
|
134
|
+
</div>
|
135
|
+
<div id="overlay">
|
136
|
+
<img id="imageDisplay" src="" alt="" />
|
137
|
+
<div id="imageInfo"></div>
|
138
|
+
</div>
|
139
|
+
<script type="text/javascript">
|
140
|
+
var overlay = document.getElementById('overlay');
|
141
|
+
var imageDisplay = document.getElementById('imageDisplay');
|
142
|
+
var imageInfo = document.getElementById('imageInfo');
|
143
|
+
var screenshotLink = document.getElementsByClassName('screenshotLink');
|
144
|
+
|
145
|
+
window.onload = setup();
|
146
|
+
|
147
|
+
function setup() {
|
148
|
+
var i, menu, tabTitles;
|
149
|
+
|
150
|
+
// Since JS is enabled, show sort menu and hide tab titles
|
151
|
+
menu = document.getElementById("sortMenu");
|
152
|
+
menu.style.display = "block";
|
153
|
+
|
154
|
+
tabTitles = document.getElementsByClassName("tabTitle");
|
155
|
+
for (i = 0; i < tabTitles.length; i++) {
|
156
|
+
tabTitles[i].style.display = "none";
|
157
|
+
}
|
158
|
+
|
159
|
+
doClick(document.getElementById("defaultTab"));
|
160
|
+
}
|
161
|
+
|
162
|
+
function getCurrentTab() {
|
163
|
+
var i, tabs;
|
164
|
+
tabs = document.getElementsByClassName("tabContent");
|
165
|
+
for (i = 0; i < tabs.length; i++) {
|
166
|
+
if (tabs[i].style.display != "none") {
|
167
|
+
return i + 1;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
return 1; // fallback
|
171
|
+
}
|
172
|
+
|
173
|
+
function openTab(evt, tabName) {
|
174
|
+
var i, tabContent, tabLinks;
|
175
|
+
tabs = document.getElementsByClassName("tabContent");
|
176
|
+
for (i = 0; i < tabs.length; i++) {
|
177
|
+
tabs[i].style.display = "none";
|
178
|
+
}
|
179
|
+
tabLinks = document.getElementsByClassName("tabLink");
|
180
|
+
for (i = 0; i < tabLinks.length; i++) {
|
181
|
+
tabLinks[i].className = tabLinks[i].className.replace(" active", "");
|
182
|
+
}
|
183
|
+
document.getElementById(tabName).style.display = "block";
|
184
|
+
evt.currentTarget.className += " active";
|
185
|
+
}
|
186
|
+
|
187
|
+
function doClick(el) {
|
188
|
+
if (document.createEvent) {
|
189
|
+
var evObj = document.createEvent('MouseEvents', true);
|
190
|
+
evObj.initMouseEvent("click", false, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
191
|
+
el.dispatchEvent(evObj);
|
192
|
+
} else if (document.createEventObject) { //IE
|
193
|
+
var evObj = document.createEventObject();
|
194
|
+
el.fireEvent('onclick', evObj);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
for (index = 0; index < screenshotLink.length; ++index) {
|
199
|
+
screenshotLink[index].addEventListener('click', function(e) {
|
200
|
+
e.preventDefault();
|
201
|
+
|
202
|
+
var img = e.target;
|
203
|
+
if (e.target.tagName == 'A') {
|
204
|
+
img = e.target.children[0];
|
205
|
+
}
|
206
|
+
|
207
|
+
// beautify
|
208
|
+
var tmpImg = new Image();
|
209
|
+
tmpImg.src = img.src;
|
210
|
+
imageDisplay.style.height = 'auto';
|
211
|
+
imageDisplay.style.width = 'auto';
|
212
|
+
imageDisplay.style.paddingTop = 0;
|
213
|
+
if (window.innerHeight < tmpImg.height) {
|
214
|
+
imageDisplay.style.height = document.documentElement.clientHeight+'px';
|
215
|
+
} else if (window.innerWidth < tmpImg.width) {
|
216
|
+
imageDisplay.style.width = document.documentElement.clientWidth;+'px';
|
217
|
+
} else {
|
218
|
+
imageDisplay.style.paddingTop = parseInt((window.innerHeight - tmpImg.height) / 2)+'px';
|
219
|
+
}
|
220
|
+
|
221
|
+
imageDisplay.src = img.src;
|
222
|
+
imageDisplay.alt = img.alt;
|
223
|
+
imageDisplay.dataset.counter = img.dataset.counter;
|
224
|
+
|
225
|
+
imageInfo.innerHTML = '<h3>'+img.alt+'</h3>';
|
226
|
+
imageInfo.innerHTML += decodeURI(img.src.split("/").pop());
|
227
|
+
imageInfo.innerHTML += '<br />'+tmpImg.height+'×'+tmpImg.width+'px';
|
228
|
+
|
229
|
+
overlay.style.display = "block";
|
230
|
+
});
|
231
|
+
}
|
232
|
+
|
233
|
+
imageDisplay.addEventListener('click', function(e) {
|
234
|
+
e.stopPropagation(); // !
|
235
|
+
|
236
|
+
overlay.style.display = "none";
|
237
|
+
|
238
|
+
img_tab = parseInt(getCurrentTab());
|
239
|
+
img_counter = parseInt(e.target.dataset.counter) + 1;
|
240
|
+
try {
|
241
|
+
link = document.body.querySelector('img[data-tab="'+img_tab+'"][data-counter="'+img_counter+'"]').parentNode;
|
242
|
+
} catch (e) {
|
243
|
+
try {
|
244
|
+
link = document.body.querySelector('img[data-tab="'+img_tab+'"][data-counter="0"]').parentNode;
|
245
|
+
} catch (e) {
|
246
|
+
return false;
|
247
|
+
}
|
248
|
+
}
|
249
|
+
doClick(link);
|
250
|
+
});
|
251
|
+
|
252
|
+
overlay.addEventListener('click', function(e) {
|
253
|
+
overlay.style.display = "none";
|
254
|
+
})
|
255
|
+
|
256
|
+
function keyPressed(e) {
|
257
|
+
e = e || window.event;
|
258
|
+
var charCode = e.keyCode || e.which;
|
259
|
+
switch(charCode) {
|
260
|
+
case 27: // Esc
|
261
|
+
overlay.style.display = "none";
|
262
|
+
break;
|
263
|
+
case 34: // Page Down
|
264
|
+
case 39: // Right arrow
|
265
|
+
case 54: // Keypad right
|
266
|
+
case 76: // l
|
267
|
+
case 102: // Keypad right
|
268
|
+
e.preventDefault();
|
269
|
+
doClick(imageDisplay);
|
270
|
+
break;
|
271
|
+
case 33: // Page up
|
272
|
+
case 37: // Left arrow
|
273
|
+
case 52: // Keypad left
|
274
|
+
case 72: // h
|
275
|
+
case 100: // Keypad left
|
276
|
+
e.preventDefault();
|
277
|
+
document.getElementById('imageDisplay').dataset.counter -= 2; // hacky
|
278
|
+
doClick(imageDisplay);
|
279
|
+
break;
|
280
|
+
}
|
281
|
+
};
|
282
|
+
document.body.addEventListener('keydown', keyPressed);
|
283
|
+
</script>
|
284
|
+
</body>
|
285
|
+
</html>
|
@@ -0,0 +1,125 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class HtmlGenerator
|
4
|
+
require 'erb'
|
5
|
+
require 'fastimage'
|
6
|
+
require 'xcresult'
|
7
|
+
require 'fastlane'
|
8
|
+
|
9
|
+
attr_accessor :screenshots_path
|
10
|
+
|
11
|
+
def initialize(params = {})
|
12
|
+
@screenshots_path = params.fetch(:screenshots_path, path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def path
|
16
|
+
Dir.pwd
|
17
|
+
end
|
18
|
+
|
19
|
+
def html_path
|
20
|
+
File.join(path, "lib", "html", "page.html.erb")
|
21
|
+
end
|
22
|
+
|
23
|
+
def result_path
|
24
|
+
path
|
25
|
+
end
|
26
|
+
# Tweet
|
27
|
+
# @return [String]
|
28
|
+
def generate
|
29
|
+
|
30
|
+
screens_path = screenshots_path
|
31
|
+
|
32
|
+
@data_by_language = {}
|
33
|
+
@data_by_screen = {}
|
34
|
+
Dir[File.join(screens_path, "*")].sort.each do |device_name_folders|
|
35
|
+
device_name = File.basename(device_name_folders)
|
36
|
+
Dir[File.join(device_name_folders, "*")].sort.each do |language_folder|
|
37
|
+
language = File.basename(language_folder)
|
38
|
+
Dir[File.join(language_folder, '*.png')].sort.each do |screenshot|
|
39
|
+
file_name = File.basename(screenshot)
|
40
|
+
available_devices.each do |key_name, output_name|
|
41
|
+
next unless device_name.include?(key_name)
|
42
|
+
# This screenshot is from this device
|
43
|
+
|
44
|
+
@data_by_language[language] ||= {}
|
45
|
+
@data_by_language[language][output_name] ||= []
|
46
|
+
|
47
|
+
screen_name = file_name.sub(key_name + '-', '').sub('.png', '')
|
48
|
+
@data_by_screen[screen_name] ||= {}
|
49
|
+
@data_by_screen[screen_name][output_name] ||= {}
|
50
|
+
|
51
|
+
resulting_path = screenshot
|
52
|
+
@data_by_language[language][output_name] << resulting_path
|
53
|
+
@data_by_screen[screen_name][output_name][language] = resulting_path
|
54
|
+
break # to not include iPhone 6 and 6 Plus (name is contained in the other name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
html = ERB.new(File.read(html_path)).result(binding) # https://web.archive.org/web/20160430190141/www.rrn.dk/rubys-erb-templating-system
|
60
|
+
|
61
|
+
export_path = "#{screens_path}/screenshots.html"
|
62
|
+
|
63
|
+
File.write(export_path, html)
|
64
|
+
|
65
|
+
export_path = File.expand_path(export_path)
|
66
|
+
p "Successfully created HTML file with an overview of all the screenshots: '#{export_path}'"
|
67
|
+
#system("open '#{export_path}'") unless Snapshot.config[:skip_open_summary]
|
68
|
+
end
|
69
|
+
|
70
|
+
def xcode_9_and_above_device_name_mappings
|
71
|
+
{
|
72
|
+
# snapshot in Xcode 9 saves screenshots with the SIMULATOR_DEVICE_NAME
|
73
|
+
# which includes spaces
|
74
|
+
'iPhone 12 Pro Max' => "iPhone 12 Pro Max",
|
75
|
+
'iPhone 12 Pro' => "iPhone 12 Pro",
|
76
|
+
'iPhone 12 mini' => "iPhone 12 mini",
|
77
|
+
'iPhone 12' => "iPhone 12",
|
78
|
+
'iPhone 11 Pro Max' => "iPhone 11 Pro Max",
|
79
|
+
'iPhone 11 Pro' => "iPhone 11 Pro",
|
80
|
+
'iPhone 11' => "iPhone 11",
|
81
|
+
'iPhone XS Max' => "iPhone XS Max",
|
82
|
+
'iPhone XS' => "iPhone XS",
|
83
|
+
'iPhone XR' => "iPhone XR",
|
84
|
+
'iPhone 8 Plus' => "iPhone 8 Plus",
|
85
|
+
'iPhone 8' => "iPhone 8",
|
86
|
+
'iPhone X' => "iPhone X",
|
87
|
+
'iPhone 7 Plus' => "iPhone 7 Plus (5.5-Inch)",
|
88
|
+
'iPhone 7' => "iPhone 7 (4.7-Inch)",
|
89
|
+
'iPhone 6s Plus' => "iPhone 6s Plus (5.5-Inch)",
|
90
|
+
'iPhone 6 Plus' => "iPhone 6 Plus (5.5-Inch)",
|
91
|
+
'iPhone 6s' => "iPhone 6s (4.7-Inch)",
|
92
|
+
'iPhone 6' => "iPhone 6 (4.7-Inch)",
|
93
|
+
'iPhone 5s' => "iPhone 5s (4-Inch)",
|
94
|
+
'iPhone 5' => "iPhone 5 (4-Inch)",
|
95
|
+
'iPhone SE' => "iPhone SE",
|
96
|
+
'iPhone 4s' => "iPhone 4s (3.5-Inch)",
|
97
|
+
'iPad 2' => 'iPad 2',
|
98
|
+
'iPad Air (3rd generation)' => 'iPad Air (3rd generation)',
|
99
|
+
'iPad Air 2' => 'iPad Air 2',
|
100
|
+
'iPad Air' => 'iPad Air',
|
101
|
+
'iPad (5th generation)' => 'iPad (5th generation)',
|
102
|
+
'iPad (7th generation)' => 'iPad (7th generation)',
|
103
|
+
'iPad Pro (9.7-inch)' => 'iPad Pro (9.7-inch)',
|
104
|
+
'iPad Pro (9.7 inch)' => 'iPad Pro (9.7-inch)', # iOS 10.3.1 simulator
|
105
|
+
'iPad Pro (10.5-inch)' => 'iPad Pro (10.5-inch)',
|
106
|
+
'iPad Pro (11-inch) (2nd generation)' => 'iPad Pro (11-inch) (2nd generation)',
|
107
|
+
'iPad Pro (11-inch)' => 'iPad Pro (11-inch)',
|
108
|
+
'iPad Pro (12.9-inch) (4th generation)' => 'iPad Pro (12.9-inch) (4th generation)',
|
109
|
+
'iPad Pro (12.9-inch) (3rd generation)' => 'iPad Pro (12.9-inch) (3rd generation)',
|
110
|
+
'iPad Pro (12.9-inch) (2nd generation)' => 'iPad Pro (12.9-inch) (2nd generation)',
|
111
|
+
'iPad Pro (12.9-inch)' => 'iPad Pro (12.9-inch)',
|
112
|
+
'iPad Pro (12.9 inch)' => 'iPad Pro (12.9-inch)', # iOS 10.3.1 simulator
|
113
|
+
'iPad Pro' => 'iPad Pro (12.9-inch)', # iOS 9.3 simulator
|
114
|
+
'Apple TV 1080p' => 'Apple TV',
|
115
|
+
'Apple TV 4K (at 1080p)' => 'Apple TV 4K (at 1080p)',
|
116
|
+
'Apple TV 4K' => 'Apple TV 4K',
|
117
|
+
'Apple TV' => 'Apple TV',
|
118
|
+
'Mac' => 'Mac'
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def available_devices
|
123
|
+
return xcode_9_and_above_device_name_mappings
|
124
|
+
end
|
125
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xc_html_generator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kostyantin Ishchenko
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-05-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple gem that genarate html from xcparse result
|
14
|
+
email: ko7tyantin@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/html/page.html.erb
|
20
|
+
- lib/xc_html_generator.rb
|
21
|
+
homepage: https://rubygems.org/gems/xc_html_generator
|
22
|
+
licenses:
|
23
|
+
- MIT
|
24
|
+
metadata: {}
|
25
|
+
post_install_message:
|
26
|
+
rdoc_options: []
|
27
|
+
require_paths:
|
28
|
+
- lib
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
requirements: []
|
40
|
+
rubygems_version: 3.2.16
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Helper gem for xcparse
|
44
|
+
test_files: []
|