Compare commits

..

43 commits

Author SHA1 Message Date
Howland Owl
fbc59fdaaa Print the actual file that is not importing.
- prg not png: when you read png, and it's a prg for c64, this will help!
2020-04-14 10:29:40 +03:00
Howland Owl
d57b5573c9 Some... strangeness seemed to occur in Amiga ascii with these values
- however this may just be a local thing? I don't know, it seems to
 be fine when loaded over the net.
2020-04-10 02:58:05 +03:00
Howland Owl
ba66b98200 Now handles image preparsing 2020-04-10 02:18:54 +03:00
Howland Owl
e51bec4909 Actually handle a new file, and create a sahli file
- just ansi for now
2020-04-10 02:10:56 +03:00
Howland Owl
dbfb8db6d4 changes to the sauce library, to make work with python 3.
- likely needs complete overhaul, as it doesn't do latest SAUCE per burps.
2020-04-09 21:44:29 +03:00
Howland Owl
14a646e680 read sauce info. Required changes to sauce library. 2020-04-09 21:44:02 +03:00
Howland Owl
6e5c28c9c4 Refactoring the way we create blank files. 2020-04-09 19:59:12 +03:00
Howland Owl
97d1b1ebe5 Start of the editor
- class structure works, but is odd.
 - I should not commit this publicly until I do a few python classes.
2020-04-09 18:50:40 +03:00
Howland Owl
ec1905d37f Create new python editor directory (and prepare for modules) 2020-04-09 14:14:02 +03:00
Howland Owl
d7c908a033 Add .gitignore; move old javascript editor thing out of the way
- prepare for python editor
2020-04-09 14:12:24 +03:00
10bc3e132e Merge branch 'mt' of truck/Sahli into master 2020-04-09 10:54:45 +00:00
moqui
9461c59ce1
Merge pull request #9 from m0qui/master
Merge from master
2018-03-27 00:18:38 +02:00
m0qui
4c50e001ef Clean up: z works on images, ascii & ansi; e/r works on ascii & ansi; t work on images, ascii & ansi 2018-03-27 00:17:18 +02:00
m0qui
7843f2953d Clean up: z works on images, ascii & ansi; e/r works on ascii & ansi; t work on images, ascii & ansi 2018-03-27 00:13:57 +02:00
m0qui
8212f2c679 Canvas mode for Amiga/plain mode 2018-03-26 22:14:29 +02:00
m0qui
8fd83c3040 Canvas mode for Amiga/plain mode 2018-03-26 22:09:44 +02:00
m0qui
5e05d0fbb8 Added feature to increase/decrease font size in Amiga/plain mode 2018-03-26 21:54:03 +02:00
m0qui
80a92fc0c0 Added feature to increase/decrease font size in Amiga/plain mode 2018-03-26 21:41:49 +02:00
moqui
af4f9cf56b
Merge pull request #1 from lastebil/master
Merge Master
2018-03-26 20:24:06 +02:00
wtf
8f01863d39 Fix spacing in amiga/plain mode (aka <pre>) 2018-03-26 10:08:35 +02:00
Per Persson
7d5d2d5983 Merge pull request #8 from m0qui/master
Pre-revision merge
2017-04-14 12:06:20 +03:00
m0qui
68fb3c4b5a Hide mouse cursor 2017-04-08 14:48:13 +02:00
m0qui
b9363d5ec9 Bestfit mode default for filetype:image 2017-04-08 13:23:06 +02:00
m0qui
a01c9ca3b7 Bestfit mode now actually working 2017-04-08 13:12:36 +02:00
m0qui
99f6dc1504 Bestfit mode only enabled for filetype:image 2017-04-08 12:19:26 +02:00
m0qui
4bee0d69d3 Added generic picture support with best fit option 2017-03-20 09:02:41 +01:00
m0qui
df6a50ad7b Revert "Added generic picture support"
This reverts commit 4f884d9cac.
2017-03-19 14:58:15 +01:00
m0qui
4f884d9cac Added generic picture support 2017-03-18 19:27:43 +01:00
Sir Garbagetruck
ae90ebd06c Remove warning and put in the working javascript files for users (: 2016-09-27 22:44:05 +03:00
Sir Garbagetruck
8476159433 Oh yes, we need these files for people who aren't compiling themselves. 2016-09-27 22:42:25 +03:00
Sir Garbagetruck
26af6681ce Giant warning goes away, it works without f*cking with settings.
- I wonder why it works and if that means something is b0rked in firefox
2016-09-27 22:41:26 +03:00
Per Persson
58ba2141f4 Merge pull request #7 from lastebil/develop
Add 'previous' capability
2016-09-27 22:29:09 +03:00
Sir Garbagetruck
a31e4dcd9f make note that we should try to get this as an app
- should fix some of the issues with local files.
2016-09-27 22:22:26 +03:00
Sir Garbagetruck
50d2afd6d8 Move P further down help
- one shouldn't be going backward
 - with preload stuff, it could be better, then a 'pick' mode should be there
 - and that's not really what this is for.  This is for running a compo
 - compos go ONE WAY

 - yes it's good to have it as an emergency. It's a good change.
2016-09-27 22:22:01 +03:00
Sir Garbagetruck
1d6e8636ca 72 point huge ass "NOT SUPPORTED ON WINDOWS+FIREFOX" warnings.
- probably won't get read by someone ):
2016-09-27 22:14:20 +03:00
Sir Garbagetruck
d3cf696ae4 add 'previous picture' on P. 2016-09-27 22:00:46 +03:00
Sir Garbagetruck
81a25b9139 Bring in M0qui's changes (mostly going to use the P key tho) 2016-09-27 20:47:48 +03:00
moqui
54b59b6344 function to move to previous entry 2016-09-27 15:21:44 +02:00
Per Persson
a31167bd4b Merge pull request #5 from lastebil/overhaul
Fix: my tablet did not send doubleclick events, changed to 'edges'
2015-03-26 15:44:12 +02:00
Per Persson
ff0815e300 Merge pull request #4 from lastebil/overhaul
bOhEmE request for testing on mobile browser
2015-03-26 15:17:20 +02:00
Per Persson
82489faae9 Merge pull request #3 from lastebil/overhaul
all noted todo items complete except editor parts, ready for remote test by others
2015-03-25 20:54:59 +02:00
Per Persson
dd124a718b Merge pull request #2 from lastebil/overhaul
adding javascript for when you don't have coffeescript around
2015-02-28 17:32:19 +02:00
Per Persson
61d667cad5 Merge pull request #1 from lastebil/overhaul
Significantly updated, but not working 100%.

    editor needs ... much work.
    the 'panel' mode needs a proper algorithm and I'm not... getting it.
2015-02-28 17:22:08 +02:00
26 changed files with 1936 additions and 1335 deletions

179
.gitignore vendored Normal file
View file

@ -0,0 +1,179 @@
# Created by https://www.gitignore.io/api/git,emacs,python,coffeescript
# Edit at https://www.gitignore.io/?templates=git,emacs,python,coffeescript
### CoffeeScript ###
*.js
### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
dist/
# Flycheck
flycheck_*.el
# server auth directory
/server/
# projectiles files
.projectile
# directory configuration
.dir-locals.el
# network security
/network-security.data
### Git ###
# Created by git for backups. To disable backups in Git:
# $ git config --global mergetool.keepBackup false
*.orig
# Created by git when using merge tools for conflicts
*.BACKUP.*
*.BASE.*
*.LOCAL.*
*.REMOTE.*
*_BACKUP_*.txt
*_BASE_*.txt
*_LOCAL_*.txt
*_REMOTE_*.txt
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
#project settings
sahli-venv/*
*.wp*

47
Cakefile Normal file
View file

@ -0,0 +1,47 @@
fs = require 'fs'
option '-o', '--output [dir]', 'dir for compiled code'
task 'watch', 'watch current dir', (options) ->
{spawn} = require 'child_process'
args = ['-w','-c']
if options.output
args = args.concat ['./']
process.chdir __originalDirname
coffee = spawn 'coffee', args
coffee.stderr.on 'data', (data) ->
process.stderr.write data.toString()
coffee.stdout.on 'data', (data) ->
console.log data.toString()
source = [
'16col/imgtxtmode.coffee',
'16col/ansi.coffee',
'16col/bin.coffee',
'16col/idf.coffee',
'16col/adf.coffee',
'16col/sauce.coffee',
'16col/tundra.coffee',
'16col/pcboard.coffee',
'16col/avatar.coffee',
'16col/xbin.coffee',
'16col/pallette.coffee',
'16col/fonts.coffee',
]
task 'build', 'Build merged file for production', (options) ->
{exec} = require 'child_process'
content = []
for file, index in source then do (file, index) ->
fs.readFile file, 'utf8', (err, fileContents) ->
throw err if err
content[index] = fileContents
if index == source.length - 1
coffee = content.join('\n')
fs.writeFile 'textmode.coffee', coffee, 'utf8', (err) ->
throw err if err
command = 'coffee --compile textmode.coffee'
exec command, (err, stdout, stderr) ->
throw err if err
console.log stdout + stderr

View file

@ -6,7 +6,7 @@
l__________/__________|___|______l__________j_____j
Ansi/Ansi Viewer in Ecmascript
Coded by Sir Garbagetruck / Accession 2013
Coded by Sir Garbagetruck / Accession 2013+
Uses fonts by DMG, http:trueschool.se
Uses SixteenColors textmode js library for rendering
(well, my optimized version...)
@ -48,6 +48,8 @@ idea...
* Android tablets ARE considered modern; Ipad/Iphone too.
* I haven't tested on MorphOS yet.
For Chrome/Chromium:
To use with _local_ files you need to run your browser
in "developer" mode, that means:
@ -63,6 +65,30 @@ This works just fine if you use remote urls for the files.
EVERY PERSON ALIVE, DEAD, OR IMAGINARY,
INCLUDING THE NONEXISTENT. ***
Mr Doob (who I want to call Trace (: ) has a good page
explaining how to do this and alternatives here:
https://github.com/mrdoob/three.js/wiki/How-to-run-things-locally
Firefox (and Icecat, possibly other Firefox codebased browsers)
seem to work today (Sept 2016) _without_ making any changes, so
you can use it 'out of the box.' M0qui was able to, and I tested,
and so the big 72-point "not supported on Windows+Firefox" warning
goes away.
Again, DON'T FREAKING TURN OFF JAVASCRIPT SECURITY AND FORGET TO
TURN IT BACK ON. DON'T. NOT JUST ON WINDOWS. BUT ESPECIALLY ON
WINDOWS.
I may be able to turn this into a chrome app at some point, which
will eliminate that issue. Possibly also a Firefox solution, but:
As of today: I do not support this on Windows + Firefox. That is
100% at your own risk, because of the possibility you will forget
to set the setting back.
It's just plain safer to install this on your webserver at the
party place in a directory and use _that._
This product is licensed under the WTFPL. See:
http://www.wtfpl.net
for details, or just get the license:
@ -98,3 +124,8 @@ Azzarro/Madwizards.
- More examples came from 16colors archive. When the final
Sahli ver. B comes out, I'll select some test files and
put those credits in here too.
- Thanks to M0qui for submitting a patch for 'backwards'
(in case you accidentally hit space. Which we c64 sceners
never do, because that would be the NEXT demopart, and
you'd have to reload (: )

View file

@ -0,0 +1,98 @@
label, input, textarea{
display: block;
}
input, textarea {
width: 90%;
}
textarea {
height: 8em;
}
.colorbox {
border: 0;
padding: 0;
height: 2em;
}
pre {
font-family: 'TopazPlus a500a1000a2000','mOsOul',Monaco,monospace;
font-size: 16;
border: 2px inset #808080;
}
label {
font-size: 10;
}
div ul li{
list-style-type: none
}
#list {
border: 1px solid black;
}
#formica {
font-size: medium;
}
.entry {
margin: 0 3px 3px 3px;
padding: 0.4em;
padding-left: 1.5em;
width: 95%;
height: 18px;
border: 2px outset rgb(255,228,196);
background-color: rgb(245,245,220);
}
.righty {
float: right;
}
.entry span {
display: inline-block;
}
# this does not actually change anything because the design is set by
# the jquery-ui bit. Altering in the script does work. Here for reference.
.45box {
width: 45%;
display: inline-block;
}
div.groupbox p {
margin: .25 ex;
}
#dumparea {
position: absolute;
top: 1em;
padding: 1em;
margin: 1em;
width: 90%;
height: 90%;
background: floralwhite;
border: inset 2px royalblue;
}
#sahlioutput {
font-family: 'TopazPlus a500a1000a2000','mOsOul',Monaco,monospace;
font-size: 16;
background: aliceblue;
overflow-wrap: break-word;
word-wrap: break-word;
width: 100%;
height: 95%;
padding: 1ex;
border: inset 2px royalblue;
}
#closespan {
float: right;
margin: 0px 0px 1ex;
padding: 0px;
}

View file

@ -1,57 +1,11 @@
// Generated by CoffeeScript 1.9.0
/*
Sahli Editor
============
Editor for Sahli files.
- open existing file
- create new item
* get filename from dir
* insert SAUCE data if available
* use SAUCE data to find font
* allow Amiga choices
* colorpicker
- edit existing item
- remove item
- clear whole file
- copy/clone
- move items around
- sort items
- output to screen (copy into file)
* run from node - save filename dialog
***
It should be noted that this does not do bounds checking, and it would be very
possible to overflow this by using a debugger and such. As the purpose of this
is limited, and this should NOT be put on a live website, I feel that is ok for
now. Perhaps I will fix it after Revision.
***
== Create Initial crappage
We need to make a screen that has a few things in it for starters
Title, load existing, and new file options.
Silliness for checking that this works.
*/
// Generated by CoffeeScript 1.11.0
(function() {
var Emptyfiledef, Sahli, ansiorascii, arraytocolor, booltoint, colorindex, colortoarray, colortoname, dec2hex, dumpjson, getfilelist, hex2dec, inttobool, loadsahli, newsahli, resolvefiletype, sahlicolor, statustobool;
var Sahli, ansiorascii, arraytocolor, booltoint, colorindex, colortoarray, colortoname, dec2hex, dumpjson, emptyfiledef, getfilelist, hex2dec, inttobool, loadsahli, newsahli, resolvefiletype, sahlicolor, statustobool;
$(function() {
return $("h1").hide().slideDown(500);
});
/*
Create buttons to choose between the New and Load functionalities
(As we aren't going to ever load a file _and_ do a new file.)
(If someone wants to do that, they can restart with F5 or something.)
Also hide the editor until needed, and initialize some elements.
*/
$(function() {
return $("#newsahli").button({
disabled: false
@ -86,23 +40,17 @@ Silliness for checking that this works.
}
});
$(".45box").css({
width: '40ex',
width: '45%',
display: 'inline-block'
});
$(".groupbox p").css({
margin: "0 0 .25em 0"
});
$(".colorbox").change(function() {
return sahlicolor();
});
$("#entryfont").change(function() {
var font;
font = $("#entryfont").val();
if (font === "ansifont") {
font = "BlockZone";
}
return $('pre').css('font-family', font);
});
$(".colorbox").change((function(_this) {
return function() {
return sahlicolor();
};
})(this));
$("#entryfilepick").change(function() {
if (this.files[0] != null) {
return $("#entryfile").val(this.files[0].name);
@ -113,22 +61,8 @@ Silliness for checking that this works.
});
});
/*
The sahli file definition format is as follows:
"file" - the actual filename on disk, "name" - the title of the piece,
the boolean 'amiga' indicates if it is ansi or ascii (True = ascii),
width is the width (widest point of the file), author the author of the piece,
the color and bg items define the color for amiga ascii, and the font
defines the font similarly. For PC ansi, this should be 'ansifont.'
The three remaining lines are informational and optional.
The slide format is currently unused, but consists of a background picture,
a html template, and a css file.
*/
Emptyfiledef = (function() {
function Emptyfiledef() {
emptyfiledef = (function() {
function emptyfiledef() {
this.file = "";
this.name = "";
this.amiga = true;
@ -143,13 +77,13 @@ Silliness for checking that this works.
this.text = "";
}
return Emptyfiledef;
return emptyfiledef;
})();
Sahli = (function() {
function Sahli() {
this.emptyfiledef = new Emptyfiledef;
this.emptyfiledef = new emptyfiledef;
this.emptyslidesdef = {
"background": "",
"template": "",
@ -189,7 +123,8 @@ Silliness for checking that this works.
}).click((function(_this) {
return function() {
$('#sahlioutput').text(dumpjson(_this.data));
return $('#dumparea').show(100);
$('#dumparea').show(100);
return console.log(dumpjson(_this.data));
};
})(this));
$('#listlist').button({
@ -206,7 +141,7 @@ Silliness for checking that this works.
}).click((function(_this) {
return function(event) {
var newentry;
newentry = new Emptyfiledef;
newentry = new emptyfiledef;
_this.data.filedata.push(newentry);
return _this.buildlist(_this.data);
};
@ -228,19 +163,19 @@ Silliness for checking that this works.
};
Sahli.prototype.buildlist = function(data) {
var i, item, x, _i, _j, _len, _len1, _ref, _ref1;
var i, item, j, k, len, len1, ref, ref1, x;
$('#list').show(100);
$('#list ol li').remove();
_ref = this.data.filedata;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
i = _ref[_i];
ref = this.data.filedata;
for (j = 0, len = ref.length; j < len; j++) {
i = ref[j];
console.log(i.author);
}
x = 0;
$('#dirlocation').val(this.data.location);
_ref1 = this.data.filedata;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
item = _ref1[_j];
ref1 = this.data.filedata;
for (k = 0, len1 = ref1.length; k < len1; k++) {
item = ref1[k];
$('#sortlist').append(this.additem(item, x++));
}
return $('#sortlist').sortable({
@ -251,11 +186,16 @@ Silliness for checking that this works.
},
stop: (function(_this) {
return function(event, ui) {
var a, e, s;
a = 2;
var e, l, len2, name, ref2, s;
s = ui.item.data().startpos;
e = ui.item.index();
_this.data.filedata = _this.rearrangearray(s, e, _this.data.filedata);
ref2 = _this.data.filedata;
for (l = 0, len2 = ref2.length; l < len2; l++) {
name = ref2[l];
console.log(name.author, name.name, name.file);
}
console.log('---');
return _this.buildlist(_this.data);
};
})(this)
@ -281,7 +221,7 @@ Silliness for checking that this works.
};
Sahli.prototype.genentryline = function(item, pos) {
var amigastatus, arrows, delbutton, entry, whichone;
var amigastatus, arrows, delbutton, entry;
arrows = "<span class='ui-icon ui-icon-arrowthick-2-n-s'></span>";
amigastatus = ansiorascii(booltoint(item.amiga));
delbutton = $("<span class='righty' id=del-" + pos + ">delete</span>").click((function(_this) {
@ -291,9 +231,7 @@ Silliness for checking that this works.
return _this.buildlist(_this.data);
};
})(this));
whichone = "<li class='entry' id='" + item.file + "'>" + arrows + amigastatus + " |";
whichone += " " + item.author + " : " + item.name + " : " + item.file + "</li>";
entry = $(whichone);
entry = $("<li class='entry' id='" + item.file + "'>" + arrows + amigastatus + " | " + item.author + " : " + item.name + " : " + item.file + "</li>");
return entry.append(delbutton);
};
@ -304,15 +242,13 @@ Silliness for checking that this works.
entry.name = $("#entryname").val();
entry.author = $("#entryauthor").val();
entry.amiga = statustobool($("#entryamiga").children()[1].textContent);
console.log($("#entryamiga").children()[1].textContent);
console.log(entry.amiga, entry.author);
console.log($("#entryamiga").children()[1].textContent, entry.amiga, entry.author);
entry.color = colortoarray($("#entrycolor").val());
entry.bg = colortoarray($("#entrybg").val());
entry.width = $("#entrywidth").val();
entry.line1 = $("#entryline1").val();
entry.line2 = $("#entryline2").val();
entry.text = $("#entrytext").val();
entry.font = $("#entryfont").val();
entry.file = $("#entryfile").val();
entry.filetype = $("#entryfiletype").val();
return this.buildlist(this.data);
@ -375,20 +311,10 @@ Silliness for checking that this works.
})();
/*
A Helper function to dump json out of an object as text:
*/
dumpjson = function(obj) {
return JSON.stringify(obj, null, "\t");
};
/*
Boolean / integer Helpers
*/
booltoint = function(bool) {
return bool + 1 - 1;
};
@ -405,11 +331,6 @@ Silliness for checking that this works.
}
};
/*
Resolve filetype offset in array:
*/
resolvefiletype = function(filetype) {
var options;
options = {
@ -427,11 +348,6 @@ Silliness for checking that this works.
return options[filetype];
};
/*
Resolve ansi or ascii status
*/
ansiorascii = function(status) {
if (status === 0) {
return "Ansi";
@ -440,14 +356,6 @@ Silliness for checking that this works.
}
};
/*
Color conversion from array to color item:
This decimal to hex conversion only handles 00-FF but it's fine for this
purpose; we actually _want_ that limitation in the output.
*/
dec2hex = function(num) {
return "" + (('000' + num.toString(16)).slice(-2));
};
@ -459,13 +367,13 @@ Silliness for checking that this works.
arraytocolor = function(array) {
var c, x;
c = ((function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
x = array[_i];
_results.push(dec2hex(x));
var j, len, results;
results = [];
for (j = 0, len = array.length; j < len; j++) {
x = array[j];
results.push(dec2hex(x));
}
return _results;
return results;
})()).slice(0, 3).join('');
return "#" + c;
};
@ -475,23 +383,18 @@ Silliness for checking that this works.
color = color.slice(1);
c1 = [color.slice(0, 2), color.slice(2, 4), color.slice(4, 6)];
x = (function() {
var _i, _len, _results;
_results = [];
for (_i = 0, _len = c1.length; _i < _len; _i++) {
i = c1[_i];
_results.push(hex2dec(i));
var j, len, results;
results = [];
for (j = 0, len = c1.length; j < len; j++) {
i = c1[j];
results.push(hex2dec(i));
}
return _results;
return results;
})();
x.push(255);
return x;
};
/*
Need a way to convert the array back to the color name.
*/
colortoname = function(color) {
var bw, colorname, names, ret;
names = {
@ -518,11 +421,6 @@ Silliness for checking that this works.
return ret = colorname != null ? colorname : bw;
};
/*
Similarly, need to be able to get the color index.
*/
colorindex = function(colorname) {
var names;
names = {
@ -546,12 +444,6 @@ Silliness for checking that this works.
return names[colorname];
};
/*
A function for changing the fore and background colors of the sahli ascii
example
*/
sahlicolor = function() {
var bg, fg;
fg = $('#entrycolor').val();
@ -563,13 +455,6 @@ Silliness for checking that this works.
});
};
/*
Function for loading the filelist from the specified directory on the
server/filesystem.
Needs to be made into an actual real thing.
*/
getfilelist = function() {
var location;
location = $("#dirlocation").val();
@ -578,26 +463,15 @@ Silliness for checking that this works.
});
};
/*
When clicking 'New' we want to make a brand new Sahli, and then clear out
the buttons and create the editor bit as blank.
*/
newsahli = function() {
var newentry, sahli;
sahli = new Sahli;
sahli.data = sahli.empty;
newentry = new Emptyfiledef;
newentry = new emptyfiledef;
sahli.data.filedata.push(newentry);
return sahli.edit();
};
/*
And when clicking 'load' we want to load the existing sahli file.
*/
loadsahli = function() {
var sahli;
sahli = new Sahli;

View file

@ -0,0 +1,415 @@
Sahli Editor
============
Editor for Sahli files.
- open existing file
- create new item
* get filename from dir
* insert SAUCE data if available
* use SAUCE data to find font
* allow Amiga choices
* colorpicker
- edit existing item
- remove item
- clear whole file
- copy/clone
- move items around
- sort items
- output to screen (copy into file)
* run from node - save filename dialog
***
It should be noted that this does not do bounds checking, and it would be very
possible to overflow this by using a debugger and such. As the purpose of this
is limited, and this should NOT be put on a live website, I feel that is ok for
now. Perhaps I will fix it after Revision.
***
== Create Initial crappage
We need to make a screen that has a few things in it for starters
Title, load existing, and new file options.
Silliness for checking that this works.
$(-> $("h1").hide().slideDown(500))
Create buttos to choose between the New and Load functionalities
(As we aren't going to ever load a file _and_ do a new file.)
(If someone wants to do that, they can restart with F5 or something.)
Also hide the editor until needed, and initialize some elements.
$(->
$("#newsahli")
.button { disabled: false}
.click -> newsahli()
)
$(->
$("#loadsahli")
.button { disabled: false}
.click -> loadsahli()
)
$(->
$(".hidden").hide()
$("#entryamiga").button {icons: {primary:"ui-icon-gear"}}
.click ->
stuff = $(@).children()
if @.value == "1"
stuff[1].textContent = 'Ansi'
@.value = "0"
else
stuff[1].textContent = 'Ascii'
@.value = "1"
$(".45box").css {width:'45%',display:'inline-block'}
$(".groupbox p").css {margin:"0 0 .25em 0"}
$(".colorbox").change =>
sahlicolor()
$("#entryfilepick").change ->
if @.files[0]? then $("#entryfile").val @.files[0].name
$("#entryfile").click ->
$("#entryfilepick").click()
)
The sahli file definition format is as follows:
"file" - the actual filename on disk, "name" - the title of the piece,
the boolean 'amiga' indicates if it is ansi or ascii (True = ascii),
width is the width (widest point of the file), author the author of the piece,
the color and bg items define the color for amiga ascii, and the font
defines the font similarly. For PC ansi, this should be 'ansifont.'
The three remaining lines are informational and optional.
The slide format is currently unused, but consists of a background picture,
a html template, and a css file.
class emptyfiledef
constructor: ->
@file = ""
@name = ""
@amiga = true
@filetype = 'plain'
@width = ""
@author = ""
@font = "Propaz"
@color = [ 255,255,255,255 ]
@bg = [ 0,0,0,0 ]
@line1 = ""
@line2 = ""
@text = ""
class Sahli
constructor: ->
@emptyfiledef = new emptyfiledef
@emptyslidesdef = {
"background": "",
"template": "",
"css": ""
}
@empty = {
"location": "",
"slides": @emptyslidesdef,
"filedata": [ ]
}
loader: ->
$.ajax {
url: '../list.sahli',
dataType: "json",
success: (result) =>
@data = result
@.edit()
}
Editor functionality:
Close the new/load buttons - unneeded now.
list, and allow dragon-droppings for sorting. Doubleclick to edit, or use
edit button.
edit: ->
$('#buttonbox').hide()
$('#dirlocation').change (event) =>
@data.location = event.target.value
$('#listsave').button {icons: {primary:"ui-icon-disk"}}
.click =>
$('#sahlioutput').text dumpjson @data
$('#dumparea').show 100
console.log dumpjson @data
$('#listlist').button {icons: {primary:"ui-icon-folder-open"}}
.click ->
getfilelist()
$('#listappend').button {icons: {primary:"ui-icon-1-n"}}
.click (event) =>
newentry = new emptyfiledef
@data.filedata.push newentry
@buildlist @data
$('#listdisplay').button {icons: {primary:"ui-icon-refresh"}}
.click =>
@buildlist @data
$('#closespan').click ->
$(@parentElement.parentElement).hide()
$('#sahlioutput').text ''
You need to save the order, and extract these in that order; moving around
does not alter the array. Alternately, _have_ it alter the array.
@buildlist @data
buildlist: (data) ->
$('#list').show 100
$('#list ol li').remove()
console.log i.author for i in @data.filedata
x = 0
$('#dirlocation').val @data.location
$('#sortlist').append @.additem item,x++ for item in @data.filedata
$('#sortlist').sortable
start: (event,ui) ->
ui.item.data {startpos:ui.item.index()}
stop: (event,ui) =>
s = ui.item.data().startpos
e = ui.item.index()
@data.filedata = @.rearrangearray s,e,@data.filedata
console.log name.author,name.name,name.file for name in @data.filedata
console.log '---'
@buildlist @data
Given a start and and end position, pop the array element at start off and
insert it into the array at end position. A la the draggon-dropping.
rearrangearray: (startpos,endpos,a) ->
moving = a[startpos]
alen = a.length
tarr = a[0...startpos].concat a[startpos+1..-1]
tarr[0...endpos].concat [moving].concat tarr[endpos..-1]
additem: (item,pos) ->
entry = @genentryline item,pos
entry.dblclick =>
@editline item,pos
genentryline: (item,pos) ->
arrows = "<span class='ui-icon ui-icon-arrowthick-2-n-s'></span>"
amigastatus = ansiorascii booltoint item.amiga
delbutton = $("<span class='righty' id=del-#{pos}>delete</span>")
.click (event) =>
pos = event.currentTarget.id.replace "del-",""
@data.filedata.splice pos,1
@buildlist @data
entry = $("<li class='entry' id='#{item.file}'>#{arrows}#{amigastatus} | #{item.author} : #{item.name} : #{item.file}</li>")
entry.append delbutton
save: ->
pos = $("#entryindex").val()
entry = @data.filedata[pos]
entry.name = $("#entryname").val()
entry.author = $("#entryauthor").val()
entry.amiga = statustobool $("#entryamiga").children()[1].textContent
console.log $("#entryamiga").children()[1].textContent,entry.amiga,entry.author
entry.color = colortoarray $("#entrycolor").val()
entry.bg = colortoarray $("#entrybg").val()
entry.width = $("#entrywidth").val()
entry.line1 = $("#entryline1").val()
entry.line2 = $("#entryline2").val()
entry.text = $("#entrytext").val()
entry.file = $("#entryfile").val()
entry.filetype = $("#entryfiletype").val()
@buildlist @data
editline: (data,pos) ->
$("#formica").dialog {
width:'800',
modal: false,
title:"Entry #{data.file} ",
buttons: [{
text: "Cancel",
icons: {primary: 'ui-icon-trash'},
click: ->
$(@).dialog "close"
},{
text: "Save",
icons: {primary: 'ui-icon-disk'},
click: (event) =>
event.preventDefault()
@save()
event.currentTarget.previousElementSibling.click()
}]
}
data.amiga = booltoint data.amiga
fcol = colortoname arraytocolor data.color
bcol = colortoname arraytocolor data.bg
$("#entryindex").val pos
$("#entryname").val data.name
$("#entryauthor").val data.author
$("#entryfiletpye").val data.filetype
$("#entryfiletype").children()[resolvefiletype data.filetype].selected = true
$("#entryamiga").val data.amiga
$("#entryamiga").children()[1].textContent = ansiorascii data.amiga
$("#entryfont").val data.font
$("#entrycolor").val fcol
$("#entrycolor").children()[colorindex fcol ].selected = true
$("#entrybg").val bcol
$("#entrybg").children()[colorindex bcol ].selected = true
$("#entrywidth").val data.width
$("#entryline1").val data.line1
$("#entryline2").val data.line2
$("#entrytext").val data.text
$("#entryfile").val data.file
sahlicolor()
A Helper function to dump json out of an object as text:
dumpjson = (obj) ->
JSON.stringify obj,null,"\t"
Boolean / integer Helpers
booltoint = (bool) ->
bool + 1 - 1
inttobool = (intstr) ->
(intstr == 1).toString()
statustobool = (status) ->
if status is 'Ascii' then true else false
Resolve filetype offset in array:
resolvefiletype = (filetype) ->
options = {
"plain":0
"ansi":1
"xbin":2
"ice":3
"adf":4
"avatar":5
"bin":6
"idf":7
"pcboard":8
"tundra":9
}
options[filetype]
Resolve ansi or ascii status
ansiorascii = (status) ->
if status is 0 then "Ansi" else "Ascii"
Color conversion from array to color item:
This decimal to hex conversion only handles 00-FF but it's fine for this purpose;
we actually _want_ that limitation in the output.
dec2hex = (num) ->
"#{('000'+num.toString 16).slice -2}"
hex2dec = (num) ->
parseInt num,16
arraytocolor = (array) ->
c = (dec2hex x for x in array)[0..2].join ''
"##{c}"
colortoarray = (color) ->
color = color.slice(1)
c1 = [ color[0..1], color[2..3], color[4..5] ]
x = (hex2dec i for i in c1)
x.push 255
x
Need a way to convert the array back to the color name.
colortoname = (color) ->
names = {
"#E0E0E0":"Light Grey"
"#A0A0E0":"Light Blue"
"#9AFE2E":"Light Green"
"#FF0000":"Red"
"#FF8000":"Orange"
"#FFFF00":"Yellow"
"#00F000":"Green"
"#2EFEF7":"Cyan"
"#002EF7":"Blue"
"#0B0B3B":"Navy"
"#FF00FF":"Magenta"
"#8000FF":"Purple"
"#0A2A0A":"Dark Green"
"#3B3B3B":"Dark Grey"
"#FFFFFF":"White"
"#000000":"Black"
}
color = color.toUpperCase()
colorname = names[color]
bw = if hex2dec(color.slice(1)) > 8421504 then 'White' else "Black"
ret = if colorname? then colorname else bw
Similarly, need to be able to get the color index.
colorindex = (colorname) ->
names = {
"Light Grey":0
"Light Blue":1
"Light Green":2
"Red":3
"Orange":4
"Yellow":5
"Green":6
"Cyan":7
"Blue":8
"Navy":9
"Magenta":10
"Purple":11
"Dark Green":12
"Dark Grey":13
"White":14
"Black":15
}
names[colorname]
A function for changing the fore and background colors of the sahli ascii example
sahlicolor = ->
fg = $('#entrycolor').val()
bg = $('#entrybg').val()
console.log 'sahlicolor',fg,bg
$('#sahliascii').css {'color':fg,'background':bg}
Function for loading the filelist from the specified directory on the server/filesystem.
getfilelist = ->
location = $("#dirlocation").val()
$.get("../#{location}", (listing) ->
console.log listing
)
When clicking 'New' we want to make a brand new Sahli, and then clear out
the buttons and create the editor bit as blank.
newsahli = ->
sahli = new Sahli
sahli.data = sahli.empty
newentry = new emptyfiledef
sahli.data.filedata.push newentry
sahli.edit()
And when clicking 'load' we want to load the existing sahli file.
loadsahli = ->
sahli = new Sahli
sahli.loader 'list.sahli'

View file

@ -83,12 +83,12 @@
<li>
<label for="font">Font:</label>
<select id='entryfont' name="font">
<option value="Topaz1200">Topaz1200</option>
<option value="Topaz500">Topaz500</option>
<option value="mOsOul">mOsOul</option>
<option value="MicroKnight">Microknight</option>
<option value="P0t-nOodle">P0t-nOodle</option>
<option value="BlockZone">BlockZone</option>
<option value="propaz">Topaz 2.0</option>
<option value="topaz">Topaz 1.3</option>
<option value="mosoul">mOsOul</option>
<option value="microknight">Microknight</option>
<option value="pot-noodle">P0t-nOodle</option>
<option value="blockzone">BlockZone</option>
<option value="ansifont">Ansifont</option>
</select>
</li>
@ -138,11 +138,10 @@
</div>
<div class='45box'>
<pre id='sahliascii'>
ABCDEFGHIJKLMNOPQRSTUVWXYZ&gt;&lt;~`'"^&amp;eXmPl
abcdefghijklmnopqrstuvwxyz1234567890?+@
* | ___)___ 7 I | | \-~=#/ $
: |_____ | {~} ! | \__[ : #~%
; (_____j__"__l___|__|______]___; 0Oo
________________________, ._____,
| ___|___ | | | | |_____|
|_____ | _ | | |__| |
|_____|_____|___|__|______|___|
</pre>
</div>
</div>

160
editor.py Normal file
View file

@ -0,0 +1,160 @@
#!/usr/bin/env python
# coding:utf-8
"""
Author: Sir Garbagetruck --<truck@notonfire.somewhere>
Purpose: make editing the list.sahli file easier
Created: 2020/04/09
"""
import json
import argparse
import os
from sauce import SAUCE
from PIL import Image
from sahliEditorPython import sahlifile as SF
def getfilesindir(directory):
"""return the files in a directory as an array"""
for root, dirs, files, rootfd in os.fwalk(directory):
return files
def getfilenames(filedata):
"""return the file names from a sahli filedata array"""
f = []
for i in filedata:
f.append(i['file'])
return f
def getdata(filedata, name):
"""get the filedata entry where file = name"""
for i in filedata:
if i['file'] == name:
return i
return []
def getpicdata(filename):
"""extract picture data from filename"""
imagedata = Image.open(filename)
picdata = {
'width': imagedata.width,
'height': imagedata.height
}
return picdata
def getansidata(filename):
"""extract SAUCE data from filename"""
saucedata = SAUCE(filename)
ansidata = {
'author': saucedata.author,
'group': saucedata.group,
'title': saucedata.title,
'filesize': saucedata.filesize,
'comments': saucedata.comments,
'width': None,
'height': None
}
tinfonames = [saucedata.tinfo1_name,
saucedata.tinfo2_name,
saucedata.tinfo3_name,
saucedata.tinfo4_name]
tinfo = [saucedata.tinfo1,
saucedata.tinfo2,
saucedata.tinfo3,
saucedata.tinfo4]
for i in range(0, 3):
if tinfonames[i] == 'width':
ansidata['width'] = tinfo[i]
if tinfonames[i] == 'height':
ansidata['height'] = tinfo[i]
# print(tinfonames[i])
return ansidata
def getamigadata(filename):
"""try to get some form of info from file (:"""
with open(filename, encoding='latin1') as f:
ascii = f.readlines()
width = 0
for i in ascii:
if len(i) > width:
width = len(i)
return {'height': len(ascii),
'width': width}
def main(args):
"""maintain a list.sahli file"""
if args.new:
mysahli = SF.sahlifile(None)
else:
mysahli = SF.sahlifile(args.filename)
mysahli.sahli['location'] = args.directory
files = getfilesindir(args.directory)
filedata = mysahli.sahli['filedata']
filedatanames = getfilenames(filedata)
newdata = []
for i in files:
dirfile = '{}/{}'.format(args.directory, i)
if i in filedatanames:
print('found! {}'.format(i))
# todo: _if_ I ever make this a non-preparser, then... futz with
a = getansidata(dirfile)
newdata.append(getdata(filedata, i))
else:
print('not found! {}'.format(i))
suf = i.split('.')[-1]
if suf in ['png', 'jpg', 'jpeg', 'gif',
'PNG', 'JPG', 'JPEG', 'GIF']:
stuff = getpicdata(dirfile)
entry = mysahli.blank_picture()
entry['width'] = stuff['width']
entry['height'] = stuff['height']
entry['file'] = i
entry['name'] = i
newdata.append(entry)
elif suf in ['ans', 'ANS', 'BIN', 'bin', 'XB', 'xb']:
stuff = getansidata(dirfile)
entry = mysahli.blank_ansi()
entry['file'] = i
entry['name'] = stuff['title']
entry['author'] = '{}/{}'.format(
stuff['author'], stuff['group'])
entry['text'] = stuff['comments']
if stuff['height'] is not None:
entry['height'] = stuff['height']
if stuff['width'] is not None:
entry['width'] = stuff['width']
newdata.append(entry)
elif suf in ['TXT', 'ASC', 'txt', 'asc',
'NFO', 'nfo', 'diz', 'DIZ']:
stuff = getamigadata(dirfile)
entry = mysahli.blank_amiga_ascii()
entry['name'] = i
# entry['title'] = i
# entry['height'] = stuff['height']
entry['file'] = i
newdata.append(entry)
else:
print("dunno what type of file this is... {}".format(dirfile))
mysahli.sahli['filedata'] = newdata
out = json.dumps(mysahli.sahli, sort_keys=False, indent=4)
if args.outfile == '>stdout':
print(out)
else:
with open(args.outfile, 'w') as f:
json.dump(mysahli.sahli, f, sort_keys=False, indent=4)
if __name__ == '__main__':
ap = argparse.ArgumentParser()
ap.add_argument('-f', '--filename', default='list.sahli')
ap.add_argument('-n', '--new', action='store_true')
ap.add_argument('-o', '--outfile', type=str, default='>stdout')
ap.add_argument('-d', '--directory', type=str, required=True,
help='directory where compo files are')
main(ap.parse_args())

View file

@ -1,427 +0,0 @@
###
Sahli Editor
============
Editor for Sahli files.
- open existing file
- create new item
* get filename from dir
* insert SAUCE data if available
* use SAUCE data to find font
* allow Amiga choices
* colorpicker
- edit existing item
- remove item
- clear whole file
- copy/clone
- move items around
- sort items
- output to screen (copy into file)
* run from node - save filename dialog
***
It should be noted that this does not do bounds checking, and it would be very
possible to overflow this by using a debugger and such. As the purpose of this
is limited, and this should NOT be put on a live website, I feel that is ok for
now. Perhaps I will fix it after Revision.
***
== Create Initial crappage
We need to make a screen that has a few things in it for starters
Title, load existing, and new file options.
Silliness for checking that this works.
###
$(-> $("h1").hide().slideDown(500))
###
Create buttons to choose between the New and Load functionalities
(As we aren't going to ever load a file _and_ do a new file.)
(If someone wants to do that, they can restart with F5 or something.)
Also hide the editor until needed, and initialize some elements.
###
$(->
$("#newsahli")
.button { disabled: false}
.click -> newsahli()
)
$(->
$("#loadsahli")
.button { disabled: false}
.click -> loadsahli()
)
$(->
$(".hidden").hide()
$("#entryamiga").button {icons: {primary:"ui-icon-gear"}}
.click ->
stuff = $(@).children()
if @.value == "1"
stuff[1].textContent = 'Ansi'
@.value = "0"
else
stuff[1].textContent = 'Ascii'
@.value = "1"
$(".45box").css {width:'40ex',display:'inline-block'}
$(".groupbox p").css {margin:"0 0 .25em 0"}
$(".colorbox").change ->
sahlicolor()
$("#entryfont").change ->
font = $("#entryfont").val()
if font == "ansifont"
font = "BlockZone"
$('pre').css 'font-family',font
$("#entryfilepick").change ->
if @.files[0]? then $("#entryfile").val @.files[0].name
$("#entryfile").click ->
$("#entryfilepick").click()
)
###
The sahli file definition format is as follows:
"file" - the actual filename on disk, "name" - the title of the piece,
the boolean 'amiga' indicates if it is ansi or ascii (True = ascii),
width is the width (widest point of the file), author the author of the piece,
the color and bg items define the color for amiga ascii, and the font
defines the font similarly. For PC ansi, this should be 'ansifont.'
The three remaining lines are informational and optional.
The slide format is currently unused, but consists of a background picture,
a html template, and a css file.
###
class Emptyfiledef
constructor: ->
@file = ""
@name = ""
@amiga = true
@filetype = 'plain'
@width = ""
@author = ""
@font = "Propaz"
@color = [ 255,255,255,255 ]
@bg = [ 0,0,0,0 ]
@line1 = ""
@line2 = ""
@text = ""
class Sahli
constructor: ->
@emptyfiledef = new Emptyfiledef
@emptyslidesdef = {
"background": "",
"template": "",
"css": ""
}
@empty = {
"location": "",
"slides": @emptyslidesdef,
"filedata": [ ]
}
loader: ->
$.ajax {
url: '../list.sahli',
dataType: "json",
success: (result) =>
@data = result
@.edit()
}
edit: ->
$('#buttonbox').hide()
$('#dirlocation').change (event) =>
@data.location = event.target.value
$('#listsave').button {icons: {primary:"ui-icon-disk"}}
.click =>
$('#sahlioutput').text dumpjson @data
$('#dumparea').show 100
$('#listlist').button {icons: {primary:"ui-icon-folder-open"}}
.click ->
getfilelist()
$('#listappend').button {icons: {primary:"ui-icon-1-n"}}
.click (event) =>
newentry = new Emptyfiledef
@data.filedata.push newentry
@buildlist @data
$('#listdisplay').button {icons: {primary:"ui-icon-refresh"}}
.click =>
@buildlist @data
$('#closespan').click ->
$(@parentElement.parentElement).hide()
$('#sahlioutput').text ''
@buildlist @data
buildlist: (data) ->
$('#list').show 100
$('#list ol li').remove()
console.log i.author for i in @data.filedata
x = 0
$('#dirlocation').val @data.location
$('#sortlist').append @.additem item,x++ for item in @data.filedata
$('#sortlist').sortable
start: (event,ui) ->
ui.item.data
startpos:ui.item.index()
stop: (event,ui) =>
a = 2
s = ui.item.data().startpos
e = ui.item.index()
@data.filedata = @.rearrangearray s,e,@data.filedata
@buildlist @data
rearrangearray: (startpos,endpos,a) ->
moving = a[startpos]
alen = a.length
tarr = a[0...startpos].concat a[startpos+1..-1]
tarr[0...endpos].concat [moving].concat tarr[endpos..-1]
additem: (item,pos) ->
entry = @genentryline item,pos
entry.dblclick =>
@editline item,pos
genentryline: (item,pos) ->
arrows = "<span class='ui-icon ui-icon-arrowthick-2-n-s'></span>"
amigastatus = ansiorascii booltoint item.amiga
delbutton = $("<span class='righty' id=del-#{pos}>delete</span>")
.click (event) =>
pos = event.currentTarget.id.replace "del-",""
@data.filedata.splice pos,1
@buildlist @data
whichone = "<li class='entry' id='#{item.file}'>#{arrows}#{amigastatus} |"
whichone += " #{item.author} : #{item.name} : #{item.file}</li>"
entry = $(whichone)
entry.append delbutton
save: ->
pos = $("#entryindex").val()
entry = @data.filedata[pos]
entry.name = $("#entryname").val()
entry.author = $("#entryauthor").val()
entry.amiga = statustobool $("#entryamiga").children()[1].textContent
console.log $("#entryamiga").children()[1].textContent
console.log entry.amiga,entry.author
entry.color = colortoarray $("#entrycolor").val()
entry.bg = colortoarray $("#entrybg").val()
entry.width = $("#entrywidth").val()
entry.line1 = $("#entryline1").val()
entry.line2 = $("#entryline2").val()
entry.text = $("#entrytext").val()
entry.font = $("#entryfont").val()
entry.file = $("#entryfile").val()
entry.filetype = $("#entryfiletype").val()
@buildlist @data
editline: (data,pos) ->
$("#formica").dialog {
width:'800',
modal: false,
title:"Entry #{data.file} ",
buttons: [{
text: "Cancel",
icons: {primary: 'ui-icon-trash'},
click: ->
$(@).dialog "close"
},{
text: "Save",
icons: {primary: 'ui-icon-disk'},
click: (event) =>
event.preventDefault()
@save()
event.currentTarget.previousElementSibling.click()
}]
}
data.amiga = booltoint data.amiga
fcol = colortoname arraytocolor data.color
bcol = colortoname arraytocolor data.bg
$("#entryindex").val pos
$("#entryname").val data.name
$("#entryauthor").val data.author
$("#entryfiletpye").val data.filetype
$("#entryfiletype").children()[resolvefiletype data.filetype].selected =true
$("#entryamiga").val data.amiga
$("#entryamiga").children()[1].textContent = ansiorascii data.amiga
$("#entryfont").val data.font
$("#entrycolor").val fcol
$("#entrycolor").children()[colorindex fcol ].selected = true
$("#entrybg").val bcol
$("#entrybg").children()[colorindex bcol ].selected = true
$("#entrywidth").val data.width
$("#entryline1").val data.line1
$("#entryline2").val data.line2
$("#entrytext").val data.text
$("#entryfile").val data.file
sahlicolor()
###
A Helper function to dump json out of an object as text:
###
dumpjson = (obj) ->
JSON.stringify obj,null,"\t"
###
Boolean / integer Helpers
###
booltoint = (bool) ->
bool + 1 - 1
inttobool = (intstr) ->
(intstr == 1).toString()
statustobool = (status) ->
if status is 'Ascii' then true else false
###
Resolve filetype offset in array:
###
resolvefiletype = (filetype) ->
options = {
"plain":0
"ansi":1
"xbin":2
"ice":3
"adf":4
"avatar":5
"bin":6
"idf":7
"pcboard":8
"tundra":9
}
options[filetype]
###
Resolve ansi or ascii status
###
ansiorascii = (status) ->
if status is 0 then "Ansi" else "Ascii"
###
Color conversion from array to color item:
This decimal to hex conversion only handles 00-FF but it's fine for this
purpose; we actually _want_ that limitation in the output.
###
dec2hex = (num) ->
"#{('000'+num.toString 16).slice -2}"
hex2dec = (num) ->
parseInt num,16
arraytocolor = (array) ->
c = (dec2hex x for x in array)[0..2].join ''
"##{c}"
colortoarray = (color) ->
color = color.slice(1)
c1 = [ color[0..1], color[2..3], color[4..5] ]
x = (hex2dec i for i in c1)
x.push 255
x
###
Need a way to convert the array back to the color name.
###
colortoname = (color) ->
names = {
"#E0E0E0":"Light Grey"
"#A0A0E0":"Light Blue"
"#9AFE2E":"Light Green"
"#FF0000":"Red"
"#FF8000":"Orange"
"#FFFF00":"Yellow"
"#00F000":"Green"
"#2EFEF7":"Cyan"
"#002EF7":"Blue"
"#0B0B3B":"Navy"
"#FF00FF":"Magenta"
"#8000FF":"Purple"
"#0A2A0A":"Dark Green"
"#3B3B3B":"Dark Grey"
"#FFFFFF":"White"
"#000000":"Black"
}
color = color.toUpperCase()
colorname = names[color]
bw = if hex2dec(color.slice(1)) > 8421504 then 'White' else "Black"
ret = if colorname? then colorname else bw
###
Similarly, need to be able to get the color index.
###
colorindex = (colorname) ->
names = {
"Light Grey":0
"Light Blue":1
"Light Green":2
"Red":3
"Orange":4
"Yellow":5
"Green":6
"Cyan":7
"Blue":8
"Navy":9
"Magenta":10
"Purple":11
"Dark Green":12
"Dark Grey":13
"White":14
"Black":15
}
names[colorname]
###
A function for changing the fore and background colors of the sahli ascii
example
###
sahlicolor = ->
fg = $('#entrycolor').val()
bg = $('#entrybg').val()
console.log 'sahlicolor',fg,bg
$('#sahliascii').css {'color':fg,'background':bg}
###
Function for loading the filelist from the specified directory on the
server/filesystem.
Needs to be made into an actual real thing.
###
getfilelist = ->
location = $("#dirlocation").val()
$.get("../#{location}", (listing) ->
console.log listing
)
###
When clicking 'New' we want to make a brand new Sahli, and then clear out
the buttons and create the editor bit as blank.
###
newsahli = ->
sahli = new Sahli
sahli.data = sahli.empty
newentry = new Emptyfiledef
sahli.data.filedata.push newentry
sahli.edit()
###
And when clicking 'load' we want to load the existing sahli file.
###
loadsahli = ->
sahli = new Sahli
sahli.loader 'list.sahli'

View file

@ -1,231 +0,0 @@
label, input, textarea{
display: block;
}
input, textarea {
width: 90%;
}
textarea {
height: 8em;
}
.colorbox {
border: 0;
padding: 0;
height: 2em;
}
pre {
font-family: 'topaz500','mosoul',Monaco,monospace;
font-size: 16;
border: 2px inset #808080;
}
label {
font-size: 10;
}
div ul li{
list-style-type: none
}
#list {
border: 1px solid black;
}
#formica {
font-size: medium;
}
.entry {
margin: 0 3px 3px 3px;
padding: 0.4em;
padding-left: 1.5em;
width: 95%;
height: 18px;
border: 2px outset rgb(255,228,196);
background-color: rgb(245,245,220);
}
.righty {
float: right;
}
.entry span {
display: inline-block;
}
/* this does not actually change anything because the design is set by */
/* the jquery-ui bit. Altering in the script does work. Here for reference. */
/*
.45box {
width: 45%;
display: inline-block;
}
*/
div.groupbox p {
margin: .25 ex;
}
#dumparea {
position: absolute;
top: 1em;
padding: 1em;
margin: 1em;
width: 90%;
height: 90%;
background: floralwhite;
border: inset 2px royalblue;
}
#sahlioutput {
font-family: 'microknight','P0t-nOodle',Monaco,monospace;
font-size: 16;
background: aliceblue;
overflow-wrap: break-word;
word-wrap: break-word;
width: 100%;
height: 95%;
padding: 1ex;
border: inset 2px royalblue;
}
#closespan {
float: right;
margin: 0px 0px 1ex;
padding: 0px;
}
@font-face {
font-family: 'P0t-nOodle';
src: url('fonts/P0T-NOoDLE_v1.0.woff2') format('woff2');
src: url('fonts/P0T-NOoDLE_v1.0.woff') format('woff');
}
@font-face {
font-family: 'MicroKnight';
src: url('fonts/MicroKnightPlus_v1.0.woff2') format('woff2');
src: url('fonts/MicroKnightPlus_v1.0.woff') format('woff');
}
@font-face {
font-family: 'mOsOul';
src: url('fonts/mOsOul_v1.0.woff2') format('woff2');
src: url('fonts/mOsOul_v1.0.woff') format('woff');
}
@font-face {
font-family: 'Topaz1200';
src: url('fonts/TopazPlusA1200.woff') format('woff2');
src: url('fonts/TopazPlusA1200.woff') format('woff');
}
@font-face {
font-family: 'Topaz500';
src: url('fonts/TopazPlusA500.woff2') format('woff2');
src: url('fonts/TopazPlusA500.woff') format('woff');
}
@font-face {
font-family: 'blockzone';
src: url('fonts/BlockZone.woff2') format('woff2');
src: url('fonts/BlockZone.woff') format('woff');
}
.mosoul {
font-family: mOsOul;
text-align: left;
}
.pot-noodle , .p0t-noodle {
font-family: 'P0t-nOodle';
text-align: left;
}
.topaz, .topaz500 {
font-family: 'Topaz500';
text-align: left;
}
.propaz, .topaz1200 {
font-family: 'Topaz1200';
text-align: left;
}
.microknight, .microknightplus {
font-family: 'MicroKnight';
text-align: left;
}
.blockzone, .pcansifont {
font-family: 'blockzone';
text-align: left;
}
@font-face {
font-family: 'P0t-nOodle';
src: url('../fonts/P0T-NOoDLE_v1.0.woff2') format('woff2');
src: url('../fonts/P0T-NOoDLE_v1.0.woff') format('woff');
}
@font-face {
font-family: 'MicroKnight';
src: url('../fonts/MicroKnightPlus_v1.0.woff2') format('woff2');
src: url('../fonts/MicroKnightPlus_v1.0.woff') format('woff');
}
@font-face {
font-family: 'mOsOul';
src: url('../fonts/mOsOul_v1.0.woff2') format('woff2');
src: url('../fonts/mOsOul_v1.0.woff') format('woff');
}
@font-face {
font-family: 'Topaz1200';
src: url('../fonts/TopazPlusA1200.woff') format('woff2');
src: url('../fonts/TopazPlusA1200.woff') format('woff');
}
@font-face {
font-family: 'Topaz500';
src: url('../fonts/TopazPlusA500.woff2') format('woff2');
src: url('../fonts/TopazPlusA500.woff') format('woff');
}
@font-face {
font-family: 'blockzone';
src: url('../fonts/BlockZone.woff2') format('woff2');
src: url('../fonts/BlockZone.woff') format('woff');
}
.mosoul {
font-family: mOsOul;
text-align: left;
}
.pot-noodle , .p0t-noodle {
font-family: 'P0t-nOodle';
text-align: left;
}
.topaz, .topaz500 {
font-family: 'Topaz500';
text-align: left;
}
.propaz, .topaz1200 {
font-family: 'Topaz1200';
text-align: left;
}
.microknight, .microknightplus {
font-family: 'MicroKnight';
text-align: left;
}
.blockzone, .pcansifont {
font-family: 'blockzone';
text-align: left;
}

View file

@ -1,413 +0,0 @@
Sahli Editor
============
Editor for Sahli files.
- open existing file
- create new item
* get filename from dir
* insert SAUCE data if available
* use SAUCE data to find font
* allow Amiga choices
* colorpicker
- edit existing item
- remove item
- clear whole file
- copy/clone
- move items around
- sort items
- output to screen (copy into file)
* run from node - save filename dialog
***
It should be noted that this does not do bounds checking, and it would be very
possible to overflow this by using a debugger and such. As the purpose of this
is limited, and this should NOT be put on a live website, I feel that is ok for
now. Perhaps I will fix it after Revision.
***
== Create Initial crappage
We need to make a screen that has a few things in it for starters
Title, load existing, and new file options.
Silliness for checking that this works.
$(-> $("h1").hide().slideDown(500))
Create buttos to choose between the New and Load functionalities
(As we aren't going to ever load a file _and_ do a new file.)
(If someone wants to do that, they can restart with F5 or something.)
Also hide the editor until needed, and initialize some elements.
$(->
$("#newsahli")
.button { disabled: false}
.click -> newsahli()
)
$(->
$("#loadsahli")
.button { disabled: false}
.click -> loadsahli()
)
$(->
$(".hidden").hide()
$("#entryamiga").button {icons: {primary:"ui-icon-gear"}}
.click ->
stuff = $(@).children()
if @.value == "1"
stuff[1].textContent = 'Ansi'
@.value = "0"
else
stuff[1].textContent = 'Ascii'
@.value = "1"
$(".45box").css {width:'45%',display:'inline-block'}
$(".groupbox p").css {margin:"0 0 .25em 0"}
$(".colorbox").change ->
sahlicolor()
$("#entryfont").change ->
$('pre').css 'font-family',$('#entryfont').val()
$("#entryfilepick").change ->
if @.files[0]? then $("#entryfile").val @.files[0].name
$("#entryfile").click ->
$("#entryfilepick").click()
)
The sahli file definition format is as follows:
"file" - the actual filename on disk, "name" - the title of the piece,
the boolean 'amiga' indicates if it is ansi or ascii (True = ascii),
width is the width (widest point of the file), author the author of the piece,
the color and bg items define the color for amiga ascii, and the font
defines the font similarly. For PC ansi, this should be 'ansifont.'
The three remaining lines are informational and optional.
The slide format is currently unused, but consists of a background picture,
a html template, and a css file.
class Emptyfiledef
constructor: ->
@file = ""
@name = ""
@amiga = true
@filetype = 'plain'
@width = ""
@author = ""
@font = "Propaz"
@color = [ 255,255,255,255 ]
@bg = [ 0,0,0,0 ]
@line1 = ""
@line2 = ""
@text = ""
class Sahli
constructor: ->
@emptyfiledef = new Emptyfiledef
@emptyslidesdef = {
"background": "",
"template": "",
"css": ""
}
@empty = {
"location": "",
"slides": @emptyslidesdef,
"filedata": [ ]
}
loader: ->
$.ajax {
url: '../list.sahli',
dataType: "json",
success: (result) =>
@data = result
@.edit()
}
Editor functionality:
Close the new/load buttons - unneeded now.
list, and allow dragon-droppings for sorting. Doubleclick to edit, or use
edit button.
edit: ->
$('#buttonbox').hide()
$('#dirlocation').change (event) =>
@data.location = event.target.value
$('#listsave').button {icons: {primary:"ui-icon-disk"}}
.click =>
$('#sahlioutput').text dumpjson @data
$('#dumparea').show 100
console.log dumpjson @data
$('#listlist').button {icons: {primary:"ui-icon-folder-open"}}
.click ->
getfilelist()
$('#listappend').button {icons: {primary:"ui-icon-1-n"}}
.click (event) =>
newentry = new Emptyfiledef
@data.filedata.push newentry
@buildlist @data
$('#listdisplay').button {icons: {primary:"ui-icon-refresh"}}
.click =>
@buildlist @data
$('#closespan').click ->
$(@parentElement.parentElement).hide()
$('#sahlioutput').text ''
You need to save the order, and extract these in that order; moving around
does not alter the array. Alternately, _have_ it alter the array.
@buildlist @data
buildlist: (data) ->
$('#list').show 100
$('#list ol li').remove()
console.log i.author for i in @data.filedata
x = 0
$('#dirlocation').val @data.location
$('#sortlist').append @.additem item,x++ for item in @data.filedata
$('#sortlist').sortable
start: (event,ui) ->
ui.item.data {startpos:ui.item.index()}
stop: (event,ui) =>
s = ui.item.data().startpos
e = ui.item.index()
@data.filedata = @.rearrangearray s,e,@data.filedata
console.log name.author,name.name,name.file for name in @data.filedata
console.log '---'
@buildlist @data
Given a start and and end position, pop the array element at start off and
insert it into the array at end position. A la the draggon-dropping.
rearrangearray: (startpos,endpos,a) ->
moving = a[startpos]
alen = a.length
tarr = a[0...startpos].concat a[startpos+1..-1]
tarr[0...endpos].concat [moving].concat tarr[endpos..-1]
additem: (item,pos) ->
entry = @genentryline item,pos
entry.dblclick =>
@editline item,pos
genentryline: (item,pos) ->
arrows = "<span class='ui-icon ui-icon-arrowthick-2-n-s'></span>"
amigastatus = ansiorascii booltoint item.amiga
delbutton = $("<span class='righty' id=del-#{pos}>delete</span>")
.click (event) =>
pos = event.currentTarget.id.replace "del-",""
@data.filedata.splice pos,1
@buildlist @data
entry = $("<li class='entry' id='#{item.file}'>#{arrows}#{amigastatus} | #{item.author} : #{item.name} : #{item.file}</li>")
entry.append delbutton
save: ->
pos = $("#entryindex").val()
entry = @data.filedata[pos]
entry.name = $("#entryname").val()
entry.author = $("#entryauthor").val()
entry.amiga = statustobool $("#entryamiga").children()[1].textContent
console.log $("#entryamiga").children()[1].textContent,entry.amiga,entry.author
entry.color = colortoarray $("#entrycolor").val()
entry.bg = colortoarray $("#entrybg").val()
entry.width = $("#entrywidth").val()
entry.line1 = $("#entryline1").val()
entry.line2 = $("#entryline2").val()
entry.text = $("#entrytext").val()
entry.file = $("#entryfile").val()
entry.filetype = $("#entryfiletype").val()
@buildlist @data
editline: (data,pos) ->
$("#formica").dialog {
width:'800',
modal: false,
title:"Entry #{data.file} ",
buttons: [{
text: "Cancel",
icons: {primary: 'ui-icon-trash'},
click: ->
$(@).dialog "close"
},{
text: "Save",
icons: {primary: 'ui-icon-disk'},
click: (event) =>
event.preventDefault()
@save()
event.currentTarget.previousElementSibling.click()
}]
}
data.amiga = booltoint data.amiga
fcol = colortoname arraytocolor data.color
bcol = colortoname arraytocolor data.bg
$("#entryindex").val pos
$("#entryname").val data.name
$("#entryauthor").val data.author
$("#entryfiletpye").val data.filetype
$("#entryfiletype").children()[resolvefiletype data.filetype].selected = true
$("#entryamiga").val data.amiga
$("#entryamiga").children()[1].textContent = ansiorascii data.amiga
$("#entryfont").val data.font
$("#entrycolor").val fcol
$("#entrycolor").children()[colorindex fcol ].selected = true
$("#entrybg").val bcol
$("#entrybg").children()[colorindex bcol ].selected = true
$("#entrywidth").val data.width
$("#entryline1").val data.line1
$("#entryline2").val data.line2
$("#entrytext").val data.text
$("#entryfile").val data.file
sahlicolor()
A Helper function to dump json out of an object as text:
dumpjson = (obj) ->
JSON.stringify obj,null,"\t"
Boolean / integer Helpers
booltoint = (bool) ->
bool + 1 - 1
inttobool = (intstr) ->
(intstr == 1).toString()
statustobool = (status) ->
if status is 'Ascii' then true else false
Resolve filetype offset in array:
resolvefiletype = (filetype) ->
options = {
"plain":0
"ansi":1
"xbin":2
"ice":3
"adf":4
"avatar":5
"bin":6
"idf":7
"pcboard":8
"tundra":9
}
options[filetype]
Resolve ansi or ascii status
ansiorascii = (status) ->
if status is 0 then "Ansi" else "Ascii"
Color conversion from array to color item:
This decimal to hex conversion only handles 00-FF but it's fine for this
purpose; we actually _want_ that limitation in the output.
dec2hex = (num) ->
"#{('000'+num.toString 16).slice -2}"
hex2dec = (num) ->
parseInt num,16
arraytocolor = (array) ->
c = (dec2hex x for x in array)[0..2].join ''
"##{c}"
colortoarray = (color) ->
color = color.slice(1)
c1 = [ color[0..1], color[2..3], color[4..5] ]
x = (hex2dec i for i in c1)
x.push 255
x
Need a way to convert the array back to the color name.
colortoname = (color) ->
names = {
"#E0E0E0":"Light Grey"
"#A0A0E0":"Light Blue"
"#9AFE2E":"Light Green"
"#FF0000":"Red"
"#FF8000":"Orange"
"#FFFF00":"Yellow"
"#00F000":"Green"
"#2EFEF7":"Cyan"
"#002EF7":"Blue"
"#0B0B3B":"Navy"
"#FF00FF":"Magenta"
"#8000FF":"Purple"
"#0A2A0A":"Dark Green"
"#3B3B3B":"Dark Grey"
"#FFFFFF":"White"
"#000000":"Black"
}
color = color.toUpperCase()
colorname = names[color]
bw = if hex2dec(color.slice(1)) > 8421504 then 'White' else "Black"
ret = if colorname? then colorname else bw
Similarly, need to be able to get the color index.
colorindex = (colorname) ->
names = {
"Light Grey":0
"Light Blue":1
"Light Green":2
"Red":3
"Orange":4
"Yellow":5
"Green":6
"Cyan":7
"Blue":8
"Navy":9
"Magenta":10
"Purple":11
"Dark Green":12
"Dark Grey":13
"White":14
"Black":15
}
names[colorname]
A function for changing the fore and background colors of the sahli ascii
example
sahlicolor = ->
fg = $('#entrycolor').val()
bg = $('#entrybg').val()
console.log 'sahlicolor',fg,bg
$('#sahliascii').css {'color':fg,'background':bg}
Function for loading the filelist from the specified directory on the
server/filesystem.
getfilelist = ->
location = $("#dirlocation").val()
$.get("../#{location}", (listing) ->
console.log listing
)
When clicking 'New' we want to make a brand new Sahli, and then clear out
the buttons and create the editor bit as blank.
newsahli = ->
sahli = new Sahli
sahli.data = sahli.empty
newentry = new Emptyfiledef
sahli.data.filedata.push newentry
sahli.edit()
And when clicking 'load' we want to load the existing sahli file.
loadsahli = ->
sahli = new Sahli
sahli.loader 'list.sahli'

View file

@ -41,6 +41,8 @@
<li><span class="key">W</span> Begin scrolling upward</li>
<li><span class="key">A</span> Stop scrolling</li>
<li><span class="key">P</span> Previous Picture</li>
<li><span class="key">T</span> Jump to Top of picture (resets zoom)</li>
<li><span class="key">B</span> Jump to Bottom</li>
<li><span class="key">1</span><span class="key">2</span><span class="key">3</span><span class="key">4</span><span class="key">5</span> Alter scrollspeed (fast -> slow)</li>

View file

@ -14,100 +14,104 @@
"filedata": [
{
"file": "AD - Green Beam.scaled.png",
"name": "Green Beam",
"amiga": false,
"filetype": "image",
"width": "1600",
"author": "AD",
"font": "Propaz",
"color": [
0,
0,
0,
255
],
"bg": [
255,
255,
255,
255
],
"line1": "",
"line2": "",
"text": ""
},
{
"file": "om-boss.png",
"name": "Green Beam",
"amiga": false,
"filetype": "image",
"width": "640",
"author": "AD",
"font": "Propaz",
"color": [
0,
0,
0,
255
],
"bg": [
255,
255,
255,
255
],
"line1": "",
"line2": "",
"text": ""
},
{
"file": "spaceflight.asc",
"name": "Spaceflight",
"amiga": true,
"filetype": "plain",
"width": "80",
"author": "Urs",
"font": "pot-noodle",
"color": [
255,
128,
0,
255
],
"bg": [
0,
0,
0,
255
],
"line1": "Orange on Dark Grey",
"line2": "Test for plain files",
"text": ""
},
{
"file": "az0!-revi510n.txt",
"name": "Revision",
"amiga": true,
"filetype": "plain",
"width": "80",
"author": "Azzarro/Madwizards",
"font": "Propaz",
"color": [
"font": "mosoul",
"color": [
0,
240,
0,
255
],
"bg": [
255,
0,
0,
255
],
"line1": "Azzaro Returns",
"line2": "Revision ansi/ascii compo 2013",
"text": "Color test as well as Microknight test."
"text": "Color test as well as mOsOul test."
},
{
"file": "dS!-JUFV.txt",

View file

@ -14,6 +14,7 @@ l__________/__________|___|______l__________j_____j
class @Sahli
constructor: () ->
$('body').css('cursor', 'none');
# I don't think we actually are going to have one, as we don't
# need instance variables (things used outside the function)
@ -39,6 +40,8 @@ class @Sahli
@loadhugeansi picdata, inserthere
when 'tundra'
@loadhugeansi picdata, inserthere
when 'image'
@loadpicture picdata, inserthere
else
@loadplain picdata, inserthere
@ -49,6 +52,7 @@ class @Sahli
buf = $('<span>')
buf.css {'margin':'0 auto'}
ptxt = $('<pre>')
ptxt.addClass 'plaintext'
color = @calccolor(picdata.color)
bgcolor = @calccolor(picdata.bg)
pdiv.addClass 'scrolly'
@ -58,9 +62,9 @@ class @Sahli
'background-color': bgcolor
'margin': 'auto'
'display': 'inline-block'
ptxt.width picdata.width * 8
@origwidth = ptxt.width
pdiv.width ptxt.width
#ptxt.width picdata.width * 8
#@origwidth = ptxt.width
#pdiv.width ptxt.width
pdiv.prepend buf.clone()
pdiv.append ptxt
pdiv.append buf
@ -78,6 +82,72 @@ class @Sahli
req.open 'GET', fname, true
req.send null
@increaseFont = (node, increaseBy=5) ->
current_size = parseInt($(node).css("font-size"));
$(node).css("font-size", current_size + increaseBy);
@loadpicture = (picdata, inserthere) ->
fname = @location + '/' + picdata.file
pdiv = $('<div>')
pdiv.addClass 'scrolly'
pdiv.addClass 'image'
pdiv.width window.innerWidth
pdiv.css 'display', 'inline-block'
pimg = $('<img src="' + fname + '" />')
pimg.addClass 'fullwidth'
pdiv.append pimg
inserthere.after pdiv
$('h6').hide()
$('body').scrollTop 0
@origwidth = picdata.width
@origheight = picdata.height
@bestfit()
@fullwidthplain = =>
if ($('pre').css("font-size") == "16px")
$('pre').css("font-size", "2.5vw");
else
$('pre').css("font-size", "16px");
@togglefullwidthmode = =>
if ($('pre').hasClass('plaintext'))
@fullwidthplain()
else
if $('div.scrolly').hasClass('image')
@bestfit()
else
@zoom()
@zoomin = =>
if ($('pre').hasClass('plaintext'))
@increaseFont($('pre'), 2)
else
@zoom(100);
@zoomout = =>
if ($('pre').hasClass('plaintext'))
@increaseFont($('pre'), -2)
else
@zoom(-100);
@bestfit = =>
if $('div.scrolly').hasClass('image')
if $('div.scrolly').hasClass('bestfitMode')
$('div.scrolly').removeClass 'bestfitMode'
$('div.scrolly').addClass 'fullwidthMode'
$('div.scrolly').width window.innerWidth
$('div.scrolly').height("")
$('img.bestfit').addClass 'fullwidth'
$('img.bestfit').removeClass 'bestfit'
else
$('h6').hide()
$('div.scrolly').addClass 'bestfitMode'
$('div.scrolly').removeClass 'fullwidthMode'
$('div.scrolly').width window.innerWidth
$('div.scrolly').height window.innerHeight
$('img.fullwidth').addClass 'bestfit'
$('img.fullwidth').removeClass 'fullwidth'
@loadhugeansi = (picdata, inserthere) ->
fname = @location + '/' + picdata.file
pdiv = $('<div>')
@ -97,7 +167,7 @@ class @Sahli
@origwidth = canvwidth
@origheight = calcheight
pdiv.width canvwidth
), 30, 'bits': '8'
), 30, {'bits': '8', "font": picdata.font}
@loadavatar = (picdata, inserthere) ->
console.log 'avatar', picdata, inserthere
@ -137,6 +207,7 @@ class @Sahli
filedata = @filedata
filedata[i].pic = $('<h6>' + filedata[i].file + '</h6>')
viewbox.append filedata[i].pic
$('h6').show()
@loadpic filedata[i], filedata[i].pic
@currentpic += 1
if @currentpic > filedata.length - 1
@ -146,6 +217,13 @@ class @Sahli
$('body').stop()
@loadinfopanel i
@prevpic = =>
i = @currentpic-2
if i < 0
i = i + @filedata.length
@currentpic = i
@nextpic()
@togglefullscreen = ->
docElm = document.documentElement
if @fullscreen
@ -230,7 +308,7 @@ class @Sahli
zoomee.width newwidth
$('canvas').width newwidth
else
if zoomee.width() != @origwidth
if parseInt( zoomee.width(), 10 ) != parseInt( @origwidth, 10)
zoomee.width @origwidth
$('canvas').width '100%'
else
@ -315,24 +393,26 @@ class @Sahli
switch ev.which
when @keycode ' '
@nextpic()
when @keycode 'p'
@prevpic()
when @keycode 'f'
@togglefullscreen()
when @keycode 's'
@setscroll()
when @keycode 't'
$('body').scrollTop 0
@zoom 0
@togglefullwidthmode()
when @keycode 'b'
$('body').scrollTop $('body').height()
when @keycode 'a'
$('body').stop()
@scroll_direction = - @scroll_direction
when @keycode 'z'
@zoom()
@togglefullwidthmode()
when @keycode 'e'
@zoom 100
@zoomin()
when @keycode 'r'
@zoom -100
@zoomout()
when @keycode 'w'
@changescrolldirection -1
when @keycode 'x'
@ -342,6 +422,7 @@ class @Sahli
when @keycode 'i'
$('div.infobox').toggle()
when @keycode 'v'
$('h6').show()
$('h6').height( (window.innerHeight - $('.scrolly').height()) / 2 )
when @keycode '1'
@changespeed 1
@ -356,6 +437,10 @@ class @Sahli
@scroll_speed = 4
when @keycode '5'
@changespeed 5
when @keycode '8'
@increaseFont($('pre'), -2)
when @keycode '9'
@increaseFont($('pre'), 2)
when 40 # down
@moveline 1
when 38 # up

View file

@ -10,6 +10,10 @@ body {
border: none;
}
pre {
line-height: 100%;
}
#top {
border: 1px solid green;
color: green;
@ -40,7 +44,7 @@ h6 {
.help {
position: fixed;
top: 1em;
left: 33%;
left: 25%;
text-align: left;
background-color: lightgrey;
border: outset darkgray;
@ -49,7 +53,19 @@ h6 {
border-radius: 8px;
font-family: topaz1200,mOsOul, Consolas, monospace;
opacity: .85;
width: 33%;
width: 50%;
}
.fullwidth {
width: 100%;
}
.bestfit {
padding: 0;
display: block;
margin: 0 auto;
max-width: 100%;
max-height: 100%;
}
.keylist {

148
sahli.js
View file

@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.9.0
// Generated by CoffeeScript 1.9.3
/*
.___________________________________, ___
@ -16,7 +16,9 @@ l__________/__________|___|______l__________j_____j
(function() {
this.Sahli = (function() {
function Sahli() {}
function Sahli() {
$('body').css('cursor', 'none');
}
Sahli.loadpic = function(picdata, inserthere) {
switch (picdata.filetype) {
@ -40,6 +42,8 @@ l__________/__________|___|______l__________j_____j
return this.loadhugeansi(picdata, inserthere);
case 'tundra':
return this.loadhugeansi(picdata, inserthere);
case 'image':
return this.loadpicture(picdata, inserthere);
default:
return this.loadplain(picdata, inserthere);
}
@ -55,6 +59,7 @@ l__________/__________|___|______l__________j_____j
'margin': '0 auto'
});
ptxt = $('<pre>');
ptxt.addClass('plaintext');
color = this.calccolor(picdata.color);
bgcolor = this.calccolor(picdata.bg);
pdiv.addClass('scrolly');
@ -65,9 +70,6 @@ l__________/__________|___|______l__________j_____j
'margin': 'auto',
'display': 'inline-block'
});
ptxt.width(picdata.width * 8);
this.origwidth = ptxt.width;
pdiv.width(ptxt.width);
pdiv.prepend(buf.clone());
pdiv.append(ptxt);
pdiv.append(buf);
@ -87,6 +89,91 @@ l__________/__________|___|______l__________j_____j
return req.send(null);
};
Sahli.increaseFont = function(node, increaseBy) {
var current_size;
if (increaseBy == null) {
increaseBy = 5;
}
current_size = parseInt($(node).css("font-size"));
return $(node).css("font-size", current_size + increaseBy);
};
Sahli.loadpicture = function(picdata, inserthere) {
var fname, pdiv, pimg;
fname = this.location + '/' + picdata.file;
pdiv = $('<div>');
pdiv.addClass('scrolly');
pdiv.addClass('image');
pdiv.width(window.innerWidth);
pdiv.css('display', 'inline-block');
pimg = $('<img src="' + fname + '" />');
pimg.addClass('fullwidth');
pdiv.append(pimg);
inserthere.after(pdiv);
$('h6').hide();
$('body').scrollTop(0);
this.origwidth = picdata.width;
this.origheight = picdata.height;
return this.bestfit();
};
Sahli.fullwidthplain = function() {
if ($('pre').css("font-size") === "16px") {
return $('pre').css("font-size", "2.5vw");
} else {
return $('pre').css("font-size", "16px");
}
};
Sahli.togglefullwidthmode = function() {
if ($('pre').hasClass('plaintext')) {
return Sahli.fullwidthplain();
} else {
if ($('div.scrolly').hasClass('image')) {
return Sahli.bestfit();
} else {
return Sahli.zoom();
}
}
};
Sahli.zoomin = function() {
if ($('pre').hasClass('plaintext')) {
return Sahli.increaseFont($('pre'), 2);
} else {
return Sahli.zoom(100);
}
};
Sahli.zoomout = function() {
if ($('pre').hasClass('plaintext')) {
return Sahli.increaseFont($('pre'), -2);
} else {
return Sahli.zoom(-100);
}
};
Sahli.bestfit = function() {
if ($('div.scrolly').hasClass('image')) {
if ($('div.scrolly').hasClass('bestfitMode')) {
$('div.scrolly').removeClass('bestfitMode');
$('div.scrolly').addClass('fullwidthMode');
$('div.scrolly').width(window.innerWidth);
$('div.scrolly').height("");
$('img.bestfit').addClass('fullwidth');
return $('img.bestfit').removeClass('bestfit');
} else {
$('h6').hide();
$('div.scrolly').addClass('bestfitMode');
$('div.scrolly').removeClass('fullwidthMode');
$('div.scrolly').width(window.innerWidth);
$('div.scrolly').height(window.innerHeight);
$('img.fullwidth').addClass('bestfit');
return $('img.fullwidth').removeClass('fullwidth');
}
}
};
Sahli.loadhugeansi = function(picdata, inserthere) {
var calcheight, canvwidth, fname, pdiv;
fname = this.location + '/' + picdata.file;
@ -111,7 +198,8 @@ l__________/__________|___|______l__________j_____j
return pdiv.width(canvwidth);
};
})(this)), 30, {
'bits': '8'
'bits': '8',
"font": picdata.font
});
};
@ -161,6 +249,7 @@ l__________/__________|___|______l__________j_____j
filedata = Sahli.filedata;
filedata[i].pic = $('<h6>' + filedata[i].file + '</h6>');
viewbox.append(filedata[i].pic);
$('h6').show();
Sahli.loadpic(filedata[i], filedata[i].pic);
Sahli.currentpic += 1;
if (Sahli.currentpic > filedata.length - 1) {
@ -172,6 +261,16 @@ l__________/__________|___|______l__________j_____j
return Sahli.loadinfopanel(i);
};
Sahli.prevpic = function() {
var i;
i = Sahli.currentpic - 2;
if (i < 0) {
i = i + Sahli.filedata.length;
}
Sahli.currentpic = i;
return Sahli.nextpic();
};
Sahli.togglefullscreen = function() {
var docElm;
docElm = document.documentElement;
@ -270,7 +369,7 @@ l__________/__________|___|______l__________j_____j
zoomee.width(newwidth);
return $('canvas').width(newwidth);
} else {
if (zoomee.width() !== this.origwidth) {
if (parseInt(zoomee.width(), 10) !== parseInt(this.origwidth, 10)) {
zoomee.width(this.origwidth);
return $('canvas').width('100%');
} else {
@ -281,7 +380,7 @@ l__________/__________|___|______l__________j_____j
};
Sahli.panelmode = function() {
var canvs, ct, drawcol, level, newheight, newwidth, numcols, numpanels, outer, panelratio, panelslotheight, panelsperslot, pic, picdpercol, screenratio, wh, ww, x, _i, _j, _len, _len1, _results;
var canvs, ct, drawcol, j, k, len, len1, level, newheight, newwidth, numcols, numpanels, outer, panelratio, panelslotheight, panelsperslot, pic, picdpercol, results, screenratio, wh, ww, x;
$('#panel').toggle();
canvs = $('canvas');
$('.scrolly').width(this.origwidth);
@ -309,9 +408,9 @@ l__________/__________|___|______l__________j_____j
drawcol = 1;
ct = 0;
outer.append(this.createpanel(1, newwidth - 6));
_results = [];
for (_i = 0, _len = canvs.length; _i < _len; _i++) {
pic = canvs[_i];
results = [];
for (j = 0, len = canvs.length; j < len; j++) {
pic = canvs[j];
$("#column" + drawcol).append(pic);
level += 1;
ct += 1;
@ -319,19 +418,19 @@ l__________/__________|___|______l__________j_____j
level = 0;
drawcol = drawcol + 1;
if (ct < numpanels) {
_results.push(outer.append(this.createpanel(drawcol, newwidth - 6)));
results.push(outer.append(this.createpanel(drawcol, newwidth - 6)));
} else {
_results.push(void 0);
results.push(void 0);
}
} else {
_results.push(void 0);
results.push(void 0);
}
}
return _results;
return results;
} else {
$('#outbox').show();
for (_j = 0, _len1 = canvs.length; _j < _len1; _j++) {
pic = canvs[_j];
for (k = 0, len1 = canvs.length; k < len1; k++) {
pic = canvs[k];
$('.scrolly').append(pic);
}
canvs.width(this.origwidth);
@ -374,24 +473,26 @@ l__________/__________|___|______l__________j_____j
switch (ev.which) {
case _this.keycode(' '):
return _this.nextpic();
case _this.keycode('p'):
return _this.prevpic();
case _this.keycode('f'):
return _this.togglefullscreen();
case _this.keycode('s'):
return _this.setscroll();
case _this.keycode('t'):
$('body').scrollTop(0);
return _this.zoom(0);
return _this.togglefullwidthmode();
case _this.keycode('b'):
return $('body').scrollTop($('body').height());
case _this.keycode('a'):
$('body').stop();
return _this.scroll_direction = -_this.scroll_direction;
case _this.keycode('z'):
return _this.zoom();
return _this.togglefullwidthmode();
case _this.keycode('e'):
return _this.zoom(100);
return _this.zoomin();
case _this.keycode('r'):
return _this.zoom(-100);
return _this.zoomout();
case _this.keycode('w'):
return _this.changescrolldirection(-1);
case _this.keycode('x'):
@ -401,6 +502,7 @@ l__________/__________|___|______l__________j_____j
case _this.keycode('i'):
return $('div.infobox').toggle();
case _this.keycode('v'):
$('h6').show();
return $('h6').height((window.innerHeight - $('.scrolly').height()) / 2);
case _this.keycode('1'):
return _this.changespeed(1);
@ -415,6 +517,10 @@ l__________/__________|___|______l__________j_____j
return _this.scroll_speed = 4;
case _this.keycode('5'):
return _this.changespeed(5);
case _this.keycode('8'):
return _this.increaseFont($('pre'), -2);
case _this.keycode('9'):
return _this.increaseFont($('pre'), 2);
case 40:
return _this.moveline(1);
case 38:

View file

View file

@ -0,0 +1,130 @@
#!/usr/bin/env python
# coding:utf-8
"""
Author: Sir Garbagetruck --<truck@whatever>
Purpose: base class for Sahli file
Created: 2020/04/09
"""
import json
########################################################################
class sahlifile:
"""the Sahli file structure and classes to futz with"""
# ----------------------------------------------------------------------
def __init__(self, filename):
"""Constructor"""
self.valid_filetypes = [
"plain",
"ansi",
"xbin",
"ice",
"adf",
"avatar",
"bin",
"idf",
"pcboard",
"tundra"
]
self.valid_fonts = [
'Propaz', 'ansifont', 'mOsOul', 'Microknight', 'p0t-nOodle'
]
if filename is not None:
with open(filename) as f:
self.sahli = json.load(f)
else:
location = self.blank_location()
slides = self.blank_slides()
filedata = []
self.sahli = {
'location': location,
'slides': slides,
'filedata': filedata
}
def blank_slides(self):
"""blank slide structure"""
slides = {
'background': '',
'template': '',
'css': ''
}
return slides
def blank_location(self):
"""blank location structure"""
return ''
def blank_picture(self):
"""Blank picture structure"""
return {
'file': '',
'name': '',
'amiga': False,
'filetype': 'image',
'width': '1600',
'author': '',
'font': 'Propaz',
'color': [0, 0, 0, 255],
'bg': [255, 255, 255, 255],
'line1': '',
'line2': '',
'text': ''
}
# ----------------------------------------------------------------------
def blank_amiga_ascii(self):
"""blank amiga ascii"""
return {
'file': '',
'name': '',
'amiga': True,
'filetype': 'plain',
'width': '80',
'author': '',
'font': 'Propaz',
'color': [250, 250, 250, 255],
'bg': [0, 0, 0, 255],
'line1': '',
'line2': '',
'text': ''
}
# ----------------------------------------------------------------------
def blank_ansi(self):
"""blank PC Ansi"""
return {
'file': '',
'name': '',
'amiga': False,
'filetype': 'ansi',
'width': '80',
'author': '',
'font': 'Propaz',
'color': [255, 255, 255, 255],
'bg': [0, 0, 0, 255],
'line1': '',
'line2': '',
'text': ''
}
def blank_filedata(self):
"""Blank filedata structure"""
filedata = {
'file': '',
'name': '',
'amiga': False,
'filetype': 'image',
'width': '',
'author': '',
'font': 'Propaz',
'color': [0, 0, 0, 255],
'bg': [255, 255, 255, 255],
'line1': '',
'line2': '',
'text': ''
}
return filedata

510
sauce.py Normal file
View file

@ -0,0 +1,510 @@
#! /usr/bin/env python
#
# _______
# ____________ _______ _\__ /_________ ___ _____
# | _ _ \ _ | ____\ _ / | |/ _ \
# | / / / / | | | /___/ _ | | / /
# |___/___/ /___/____|________|___ | |_| |___|_____/
# \__/ |___|
#
# (c) 2006-2012 Wijnand Modderman-Lenstra - https://maze.io/
#
'''
Parser for SAUCE or Standard Architecture for Universal Comment Extensions.
'''
__author__ = 'Wijnand Modderman-Lenstra <maze@pyth0n.org>'
__copyright__ = '(C) 2006-2012 Wijnand Modderman-Lenstra'
__license__ = 'LGPL'
__version__ = '1.2'
__url__ = 'https://github.com/tehmaze/sauce'
import datetime
import os
import struct
try:
from io import StringIO
except ImportError:
from io import StringIO
class SAUCE(object):
'''
Parser for SAUCE or Standard Architecture for Universal Comment Extensions,
as defined in http://www.acid.org/info/sauce/s_spec.htm.
:param filename: file name or file handle
:property author: Name or 'handle' of the creator of the file
:property datatype: Type of data
:property date: Date the file was created
:property filesize: Original filesize NOT including any information of
SAUCE
:property group: Name of the group/company the creator is employed by
:property title: Title of the file
Example::
>>> art = open('31337.ANS', 'rb')
>>> nfo = sauce.SAUCE(art)
>>> nfo.author
'maze'
...
>>> nfo.group
''
>>> nfo.group = 'mononoke'
>>> raw = str(nfo)
Saving the new file::
>>> sav = open('31337.NEW', 'wb')
>>> nfo.write(sav)
>>> # OR you can do:
>>> sav = nfo.write('31337.NEW')
'''
# template
template = (
# name default size type
('SAUCE', 'SAUCE', 5, '5s'),
('SAUCEVersion', '00', 2, '2s'),
('Title', '\x00' * 35, 35, '35s'),
('Author', '\x00' * 20, 20, '20s'),
('Group', '\x00' * 20, 20, '20s'),
('Date', '\x00' * 8, 8, '8s'),
('FileSize', [0], 4, 'I'),
('DataType', [0], 1, 'B'),
('FileType', [0], 1, 'B'),
('TInfo1', [0], 2, 'H'),
('TInfo2', [0], 2, 'H'),
('TInfo3', [0], 2, 'H'),
('TInfo4', [0], 2, 'H'),
('Comments', [0], 1, 'B'),
('Flags', [0], 1, 'B'),
('Filler', ['\x00'] * 22, 22, '22c'),
)
templates = [t[0] for t in template]
datatypes = ['None', 'Character', 'Graphics', 'Vector', 'Sound',
'BinaryText', 'XBin', 'Archive', 'Executable']
filetypes = {
'None': {
'filetype': ['Undefined'],
},
'Character': {
'filetype': ['ASCII', 'ANSi', 'ANSiMation', 'RIP', 'PCBoard',
'Avatar', 'HTML', 'Source'],
'flags': {0: 'None', 1: 'iCE Color'},
'tinfo': (
('width', 'height', None, None),
('width', 'height', None, None),
('width', 'height', None, None),
('width', 'height', 'colors', None),
('width', 'height', None, None),
('width', 'height', None, None),
(None, None, None, None),
),
},
'Graphics': {
'filetype': ['GIF', 'PCX', 'LBM/IFF', 'TGA', 'FLI', 'FLC',
'BMP', 'GL', 'DL', 'WPG', 'PNG', 'JPG', 'MPG',
'AVI'],
'tinfo': (('width', 'height', 'bpp')) * 14,
},
'Vector': {
'filetype': ['DX', 'DWG', 'WPG', '3DS'],
},
'Sound': {
'filetype': ['MOD', '669', 'STM', 'S3M', 'MTM', 'FAR', 'ULT',
'AMF', 'DMF', 'OKT', 'ROL', 'CMF', 'MIDI', 'SADT',
'VOC', 'WAV', 'SMP8', 'SMP8S', 'SMP16', 'SMP16S',
'PATCH8', 'PATCH16', 'XM', 'HSC', 'IT'],
'tinfo': ((None,)) * 16 + (('Sampling Rate',)) * 4,
},
'BinaryText': {
'flags': {0: 'None', 1: 'iCE Color'},
},
'XBin': {
'tinfo': (('width', 'height'),),
},
'Archive': {
'filetype': ['ZIP', 'ARJ', 'LZH', 'ARC', 'TAR', 'ZOO', 'RAR',
'UC2', 'PAK', 'SQZ'],
},
}
def __init__(self, filename='', data=''):
assert (filename or data), 'Need either filename or record'
if filename:
# if type(filename) == file:
# self.filehand = filename
# else:
self.filehand = open(filename, 'rb')
self._size = os.path.getsize(self.filehand.name)
else:
self._size = len(data)
self.filehand = StringIO(data)
self.record, self.data = self._read()
def __str__(self):
return ''.join(list(self._read_file()))
def _read_file(self):
# Buffered reader (generator), reads the original file without SAUCE
# record.
self.filehand.seek(0)
# Check if we have SAUCE data
if self.record:
reads, rest = divmod(self._size - 128, 1024)
else:
reads, rest = divmod(self._size, 1024)
for x in range(0, reads):
yield self.filehand.read(1024)
if rest:
yield self.filehand.read(rest)
def _read(self):
if self._size >= 128:
self.filehand.seek(self._size - 128)
record = self.filehand.read(128)
if record.startswith(b'SAUCE'):
self.filehand.seek(0)
return record, self.filehand.read(self._size - 128)
self.filehand.seek(0)
return None, self.filehand.read()
def _gets(self, key):
if self.record is None:
return None
name, default, offset, size, stype = self._template(key)
data = self.record[offset:offset + size]
data = struct.unpack(stype, data)
if stype[-1] in 'cs':
# return ''.join(data)
return data[0].decode()
elif stype[-1] in 'BI' and len(stype) == 1:
return data[0]
else:
return data
def _puts(self, key, data):
name, default, offset, size, stype = self._template(key)
#print offset, size, data, repr(struct.pack(stype, data))
if self.record is None:
self.record = self.sauce()
self.record = ''.join([
self.record[:offset],
struct.pack(stype, data),
self.record[offset + size:]
])
return self.record
def _template(self, key):
index = self.templates.index(key)
name, default, size, stype = self.template[index]
offset = sum([self.template[x][2] for x in range(0, index)])
return name, default, offset, size, stype
def sauce(self):
'''
Get the raw SAUCE record.
'''
if self.record:
return self.record
else:
data = 'SAUCE'
for name, default, size, stype in self.template[1:]:
#print stype, default
if stype[-1] in 's':
data += struct.pack(stype, default)
else:
data += struct.pack(stype, *default)
return data
def write(self, filename):
'''
Save the file including SAUCE data to the given file(handle).
'''
filename = type(filename) == file and filename or open(
filename, 'wb')
for part in self._read_file():
filename.write(part)
filename.write(self.sauce())
return filename
# SAUCE meta data
def get_author(self):
astr = self._gets('Author')
if astr is not None:
return astr.strip()
else:
return ''
def set_author(self, author):
self._puts('Author', author)
return self
def get_comments(self):
return self._gets('Comments')
def set_comments(self, comments):
self._puts('Comments', comments)
return self
def get_datatype(self):
return self._gets('DataType')
def get_datatype_str(self):
datatype = self.datatype
if datatype is None:
return None
if datatype < len(self.datatypes):
return self.datatypes[datatype]
else:
return None
def set_datatype(self, datatype):
if type(datatype) == str:
datatype = datatype.lower().title() # fOoBAR -> Foobar
datatype = self.datatypes.index(datatype)
self._puts('DataType', datatype)
return self
def get_date(self):
return self._gets('Date')
def get_date_str(self, format='%Y%m%d'):
return datetime.datetime.strptime(self.date, format)
def set_date(self, date=None, format='%Y%m%d'):
if date is None:
date = datetime.datetime.now().strftime(format)
elif type(date) in [datetime.date, datetime.datetime]:
date = date.strftime(format)
elif type(date) in [int, int, float]:
date = datetime.datetime.fromtimestamp(date).strftime(format)
self._puts('Date', date)
return self
def get_filesize(self):
return self._gets('FileSize')
def set_filesize(self, size):
self._puts('FileSize', size)
def get_filler(self):
return self._gets('Filler')
def get_filler_str(self):
filler = self._gets('Filler')
if filler is None:
return ''
else:
return filler.rstrip('\x00')
def get_filetype(self):
return self._gets('FileType')
def get_filetype_str(self):
datatype = self.datatype_str
filetype = self.filetype
if datatype is None or filetype is None:
return None
if datatype in self.filetypes and \
'filetype' in self.filetypes[datatype] and \
filetype < len(self.filetypes[datatype]['filetype']):
return self.filetypes[datatype]['filetype'][filetype]
else:
return None
def set_filetype(self, filetype):
datatype = self.datatype_str
if type(filetype) == str:
filetype = filetype.lower().title() # fOoBAR -> Foobar
filetype = [name.lower().title()
for name in self.filetypes[datatype]['filetype']].index(filetype)
self._puts('FileType', filetype)
return self
def get_flags(self):
return self._gets('Flags')
def set_flags(self, flags):
self._puts('Flags', flags)
return self
def get_flags_str(self):
datatype = self.datatype_str
filetype = self.filetype
if datatype is None or filetype is None:
return None
if datatype in self.filetypes and \
'flags' in self.filetypes[datatype] and \
filetype < len(self.filetypes[datatype]['filetype']):
return self.filetypes[datatype]['filetype'][filetype]
else:
return None
def get_group(self):
gstr = self._gets('Group')
if gstr is not None:
return gstr.strip()
else:
return ''
# return self._gets('Group').strip()
def set_group(self, group):
self._puts('Group', group)
return self
def _get_tinfo_name(self, i):
datatype = self.datatype_str
filetype = self.filetype
if datatype is None or filetype is None:
return None
try:
return self.filetypes[datatype]['tinfo'][filetype][i - 1]
except (KeyError, IndexError):
return ''
def get_tinfo1(self):
tinfo = self._gets('TInfo1')
if tinfo is not None:
return tinfo[0]
else:
return ''
def get_tinfo1_name(self):
return self._get_tinfo_name(1)
def set_tinfo1(self, tinfo):
self._puts('TInfo1', tinfo)
return self
def get_tinfo2(self):
tinfo = self._gets('TInfo2')
if tinfo is not None:
return tinfo[0]
else:
return ''
def get_tinfo2_name(self):
return self._get_tinfo_name(2)
def set_tinfo2(self, tinfo):
self._puts('TInfo2', tinfo)
return self
def get_tinfo3(self):
tinfo = self._gets('TInfo3')
if tinfo is not None:
return tinfo[0]
return ''
def get_tinfo3_name(self):
return self._get_tinfo_name(3)
def set_tinfo3(self, tinfo):
self._puts('TInfo3', tinfo)
return self
def get_tinfo4(self):
tinfo = self._gets('TInfo4')
if tinfo is not None:
return tinfo[0]
return ''
def get_tinfo4_name(self):
return self._get_tinfo_name(4)
def set_tinfo4(self, tinfo):
self._puts('TInfo4', tinfo)
return self
def get_title(self):
tstr = self._gets('Title')
if tstr is not None:
return tstr.strip()
else:
return ''
# return self._gets('Title').strip()
def set_title(self, title):
self._puts('Title', title)
return self
def get_version(self):
return self._gets('SAUCEVersion')
def set_version(self, version):
self._puts('SAUCEVersion', version)
return self
# properties
author = property(get_author, set_author)
comments = property(get_comments, set_comments)
datatype = property(get_datatype, set_datatype)
datatype_str = property(get_datatype_str)
date = property(get_date, set_date)
filesize = property(get_filesize, set_filesize)
filetype = property(get_filetype, set_filetype)
filetype_str = property(get_filetype_str)
filler = property(get_filler)
filler_str = property(get_filler_str)
flags = property(get_flags, set_flags)
flags_str = property(get_flags_str)
group = property(get_group, set_group)
tinfo1 = property(get_tinfo1, set_tinfo1)
tinfo1_name = property(get_tinfo1_name)
tinfo2 = property(get_tinfo2, set_tinfo2)
tinfo2_name = property(get_tinfo2_name)
tinfo3 = property(get_tinfo3, set_tinfo3)
tinfo3_name = property(get_tinfo3_name)
tinfo4 = property(get_tinfo4, set_tinfo4)
tinfo4_name = property(get_tinfo4_name)
title = property(get_title, set_title)
version = property(get_version)
if __name__ == '__main__':
import sys
if len(sys.argv) != 2:
print('%s <file>' % (sys.argv[0],), file=sys.stderr)
sys.exit(1)
else:
test = SAUCE(sys.argv[1])
def show(sauce):
print('Version.:', sauce.version)
print('Title...:', sauce.title)
print('Author..:', sauce.author)
print('Group...:', sauce.group)
print('Date....:', sauce.date)
print('FileSize:', sauce.filesize)
print('DataType:', sauce.datatype, sauce.datatype_str)
print('FileType:', sauce.filetype, sauce.filetype_str)
print('TInfo1..:', sauce.tinfo1)
print('TInfo2..:', sauce.tinfo2)
print('TInfo3..:', sauce.tinfo3)
print('TInfo4..:', sauce.tinfo4)
print('Flags...:', sauce.flags, sauce.flags_str)
print('Record..:', len(sauce.record), repr(sauce.record))
print('Filler..:', sauce.filler_str)
if test.record:
show(test)
else:
print('No SAUCE record found')
test = SAUCE(data=test.sauce())
show(test)

15
setup.py Normal file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env python
# coding:utf-8
"""
Author: Sir Garbagetruck --<truck@whatever>
Purpose: setup script for Sahli editor tools
Created: 2020/04/09
"""
from setuptools import setup, find_packages
setup(
name="SahliEditor",
version="0.1",
packages=find_packages()
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
testshow/om-boss.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -7,3 +7,4 @@
(C) SAHLI ansi & ascii for load page
(C) redo load page (not popup, info)
(B) Preload
(C) Chrome app