mirror of
https://github.com/publiclab/image-sequencer.git
synced 2025-12-08 17:30:01 +01:00
Compare commits
66 Commits
MargaretAN
...
test-ui
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d65c7be7d5 | ||
|
|
045ec38c54 | ||
|
|
3081dccf19 | ||
|
|
fa047ce6a9 | ||
|
|
d0bf9de71a | ||
|
|
0cd3156c06 | ||
|
|
8880a580dd | ||
|
|
c445070937 | ||
|
|
d792f21147 | ||
|
|
ad60c91d6b | ||
|
|
3c2d6542dc | ||
|
|
b64e7cefc0 | ||
|
|
eb3b3df800 | ||
|
|
0e6e1837a6 | ||
|
|
dc361a3ab8 | ||
|
|
3d2d7844b6 | ||
|
|
8fd4efc621 | ||
|
|
413a235594 | ||
|
|
0e87c8b1df | ||
|
|
4fd814dd95 | ||
|
|
17d79c4b44 | ||
|
|
85a53325d2 | ||
|
|
81719a9e13 | ||
|
|
fc02e7aea0 | ||
|
|
f68983d6d7 | ||
|
|
b5fcba3c54 | ||
|
|
f6b1f7b201 | ||
|
|
2399e511a0 | ||
|
|
cfdb54359c | ||
|
|
9e5f252fd4 | ||
|
|
2e9689b905 | ||
|
|
c72beb7359 | ||
|
|
e5d26815d7 | ||
|
|
73b917f036 | ||
|
|
0248bc7124 | ||
|
|
89345f32b3 | ||
|
|
4e5f8728fa | ||
|
|
c2477bc3f7 | ||
|
|
ef4a4d3055 | ||
|
|
20d49456fd | ||
|
|
2aa7e9b96c | ||
|
|
52c9c35398 | ||
|
|
a522e13613 | ||
|
|
f41f564bd9 | ||
|
|
1a98247858 | ||
|
|
4369137336 | ||
|
|
595d66ecd5 | ||
|
|
6d9f656a1e | ||
|
|
69ed689ad7 | ||
|
|
107b4c22e4 | ||
|
|
e5d36ca317 | ||
|
|
eb595d6139 | ||
|
|
2bdd532848 | ||
|
|
d104ea744b | ||
|
|
bc122af258 | ||
|
|
11476d5084 | ||
|
|
a2157be2da | ||
|
|
b71e9dec12 | ||
|
|
aad1f823d3 | ||
|
|
b520622bfd | ||
|
|
6028520197 | ||
|
|
a60acd5a72 | ||
|
|
0fc8007e79 | ||
|
|
5bdaea3688 | ||
|
|
e353465dce | ||
|
|
39c70d1304 |
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -2,10 +2,10 @@ Fixes #[Add issue number here.]
|
||||
|
||||
Make sure these boxes are checked before your pull request (PR) is ready to be reviewed and merged. Thanks!
|
||||
|
||||
* [ ] tests pass -- look for a green checkbox ✔️ a few minutes after opening your PR -- or run tests locally with `rake test`
|
||||
* [ ] tests pass -- look for a green checkbox ✔️ a few minutes after opening your PR -- or run tests locally with `npm test`
|
||||
* [ ] code is in uniquely-named feature branch and has no merge conflicts
|
||||
* [ ] PR is descriptively titled
|
||||
* [ ] ask `@publiclab/reviewers` for help, in a comment below
|
||||
* [ ] ask `@publiclab/reviewers` and `@publiclab/is-reviewers` for help, in a comment below
|
||||
|
||||
> We're happy to help you get this ready -- don't be afraid to ask for help, and **don't be discouraged** if your tests fail at first!
|
||||
|
||||
|
||||
2
.github/config.yml
vendored
2
.github/config.yml
vendored
@@ -10,7 +10,7 @@ newIssueWelcomeComment: |
|
||||
|
||||
# Comment to be posted to on PRs from first time contributors in your repository
|
||||
newPRWelcomeComment: |
|
||||
Thanks for opening this pull request! `Dangerbot` will test out your code and reply in a bit with some pointers and requests.
|
||||
Thanks for opening this pull request!
|
||||
There may be some errors, **but don't worry!** We're here to help! 👍🎉😄
|
||||
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
||||
|
||||
|
||||
11
.travis.yml
11
.travis.yml
@@ -1,16 +1,21 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '4'
|
||||
- '5'
|
||||
- '6'
|
||||
- '7' # Node.js 7 is most stable version
|
||||
- '8'
|
||||
- '10'
|
||||
env:
|
||||
- CXX=g++-4.8
|
||||
before_script:
|
||||
- npm install grunt-cli -g # for "grunt build"
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
- chmod +x ./cc-test-reporter
|
||||
- ./cc-test-reporter before-build
|
||||
script:
|
||||
- npm test
|
||||
- npm run test-ui
|
||||
- grunt build
|
||||
after_script:
|
||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
|
||||
113
CODE_OF_CONDUCT.md
Normal file
113
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,113 @@
|
||||
This document was copied from its home at https://publiclab.org/conduct on October 12, 2017. See that page if you would like to submit your concerns in a safe, completely anonymous way, and to learn more about this document.
|
||||
|
||||
****
|
||||
|
||||
# Public Lab Code of Conduct
|
||||
|
||||
_Public Lab, PO Box 426113, Cambridge, MA 02142_
|
||||
|
||||
We are coming together with an intent to care for ourselves and one another. We want to nurture a compassionate democratic culture where responsibility is shared. We -- visitors, community members, community moderators, staff, organizers, sponsors, and all others -- hold ourselves accountable to the same values regardless of position or experience. For this to work for everybody, individual decisions will not be allowed to run counter to the welfare of other people. This community aspires to be a respectful place both during online and in-person interactions so that all people are able to fully participate with their dignity intact. This document is a piece of the culture we're creating.
|
||||
|
||||
|
||||
This code of conduct applies to all spaces managed by the Public Lab community and non-profit, both online and in person. It was written by the Conduct Committee (formed in 2015 during Public Lab’s annual conference “The Barnraising”) and facilitated by staff to provide a clear set of practical guidelines for multi-day events such as Barnraisings, events led by organizers and community members, and online venues such as the website, comment threads on software platforms, chatrooms, our mailing lists, the issue tracker, and any other forums created by Public Lab which the community uses for communication.
|
||||
|
||||
|
||||
## We come from all kinds of backgrounds
|
||||
|
||||
Our community is best when we fully invite and include participants from a wide range of backgrounds. We specifically design spaces to be welcoming and accessible to newcomers and folks from underrepresented groups. Public Lab is dedicated to providing a harassment-free, safe, and inclusive experience for everyone, regardless of personal and professional background, gender, gender identity and expression, style of clothing, sexual orientation, dis-/ability, physical appearance, body size, race, class, age, or religion. Public Lab resists and rejects: racism, sexism, ableism, ageism, homophobia, transphobia, body shaming, religion shaming, “geekier-than-thou” shaming, education bias, the shaming of people nursing children, and the dismissal or bullying of children or adults.
|
||||
|
||||
## We do not tolerate harassment or shaming
|
||||
|
||||
While we operate under the assumption that all people involved with Public Lab subscribe to the basic understanding laid out above, we take these issues very seriously and think they should, in general, be taken seriously. Therefore, individuals who violate this Code both in and outside of Public Lab spaces may affect their ability to participate in Public Lab ranging from temporarily being placed into online moderation to, as a last resort, expulsion from the community. If you have any questions about our commitment to this framework and/or if you are unsure about aspects of it, email conduct@publiclab.org and we will do our best to provide clarification.
|
||||
|
||||
## How It Works
|
||||
|
||||
Sometimes things go wrong. When a situation is uncomfortable, hurtful, exclusionary, or upsetting, there is a problem that should be addressed. This code of conduct is an effort to maintain a safe space for everyone, and to talk about what might happen if that space is compromised. Please see additional guidelines below for community behavior on how we expect people to interact with one another.
|
||||
|
||||
### Two helpful groups
|
||||
|
||||
__Conduct Committee (ConductCom)__: If at any time you experience something that you are not comfortable with, you may contact the Conduct Committee. As established during the 2015 Annual Barnraising, the following individuals are on the Conduct Committee: Klie Kliebert, Carla Green, Nick Shapiro, and Shannon Dosemagen, the executive director of the Public Lab nonprofit.
|
||||
|
||||
|
||||
If you would like to have a confidential conversation, connect with ConductCom in person or email via [conduct@publiclab.org](mailto:conduct@publiclab.org). A minimum of two committee members will confer and respond as swiftly as possible. If you would prefer to speak privately with a representative of the nonprofit, please contact the executive director directly either in person or by email: [shannon@publiclab.org.](mailto:conduct@publiclab.org)
|
||||
|
||||
|
||||
To submit a report anonymously for review by ConductCom, go online via phone or computer to our anonymous “contact” app, located at [http://bit.ly/PLReport](http://bit.ly/PLReport). This contact app will be monitored daily at 8am CST during in-person events like Barnraisings and weekly at all other times. During multi-day in-person events hosted by the Public Lab non-profit, there will also be a physical suggestion box available. This box will be monitored throughout the event and can also be used to let us know if you need us to check on an anonymous online submission sooner.
|
||||
|
||||
|
||||
__Moderators Group:__ The moderators group is responsible for addressing immediate moderation issues that arise during online violations of the code over email lists and Public Lab community websites, as well as approving first-time posts and generally handling spam. Instructions on how to become a moderator, and, if you’ve been placed in moderation how to begin the process of getting out of moderation can be found at: https://publiclab.org/wiki/moderation.
|
||||
|
||||
****
|
||||
|
||||
## A Culture of Empathy
|
||||
|
||||
We begin interactions by acknowledging that we are part of a community with complementary goals. Different views are allowed to respectfully coexist in the same space. When something's happened and someone is uncomfortable, our first choice is to work through it. Endeavor to listen and appropriately adjust your behavior if someone approaches you privately with a request that you apologize or publicly requests that you stop an ongoing presentation. If someone questions your words, actions or motives, or "calls you out", hear their feedback and respond respectfully. It’s okay to not understand why something is hurtful or causes discomfort, as long as you approach it respectfully, with empathy. Repeating hurtful behavior after it has been addressed is disrespectful and is not allowed. Doing so will result in removal and subsequent banning from in-person events and being placed into moderation in online spaces.
|
||||
|
||||
### The first rule of engaging with others is consent
|
||||
During in-person gatherings, consent is important to highlight because the negotiation of consent can be subtle, and it’s easy to miss each other’s non-verbal cues, resulting in miscommunication and/or offense. During online interactions, consent can be even harder to distinguish.
|
||||
|
||||
We make guesses or assessments of consent (willingness, welcome, invitation) all the time. Then we stay open to signs that the consent isn't there. Handshakes are a clear example of consent: someone offers a hand, and you take it if you want to shake it. A friendly smile might indicate consent to start a conversation. It might not. We learn that in the interaction. Sometimes we ask directly. We are open to making mistakes, and learning from them. The more we learn to be empathetic and see other people, the more we're able to talk about consent.
|
||||
|
||||
Before you engage with someone on any level, be sure you have their consent. If your indications aren't being heard, you can also ask for help from other folks, especially Conduct Committee members and staff of the non-profit: "They aren't taking the hint. Will you help?" Turning a blind eye to hurtful interactions can be as bad for our community as the exchange itself. If you witness something, it's your responsibility to say something. This is how we keep each other accountable, encourage empathy, and keep our community safe.
|
||||
|
||||
## Guidelines for in-person community behavior
|
||||
|
||||
|
||||
Do | Don’t
|
||||
----------- | -----------
|
||||
Respectfully share what method works best for you, while giving others space to think differently and contribute other ideas | Disparage entire groups/sets of people for their beliefs or methods
|
||||
Ask permission to take pictures of and post about others on social media (see Media Consent, above)| Upload photos, tag or mention others online without their consent
|
||||
Speak your own narrative, from your own unique culture | Caricature the cultural expressions of groups you are not a member of
|
||||
Model inclusionary expertise - if others in the group appear to be “lost”, slow down; stop and ask for input | Present information in a way / at a level that no one else in the room can understand, with no attempt to include others in the discussion
|
||||
Create events that are all-ages appropriate | Use language that excludes youth and their experiences as vital contributors
|
||||
Give everyone a chance to talk, only interrupting if absolutely necessary - for example, Code of Conduct violations | Repeatedly disrupt a discussion
|
||||
Stop, listen and ask for clarification if someone perceives your behavior or presentation as violating the Code of Conduct | Ignore others’ request to stop potentially harmful behavior, even if it was an accident
|
||||
Cultivate a sense of humor based on other subjects, such as word play (especially puns!) | Joke using words related to actual or insulting descriptions of people
|
||||
Use words that accurately describe the situation - For example, “The wind was ridiculously strong!” instead of “The wind was crazy!” | Use disability and mental/emotional health terminology to describe a situation metaphorically, especially if the phrasing is meant as an insult
|
||||
Only discuss someone else’s lifestyle practices if they invite you to a conversation on the topic | Make unwelcomed comments regarding a person’s lifestyle practices, including those related to food, health, parenting, relationships, and employment
|
||||
Ask someone before you hug them; keep your hands/body to yourself, even when joking, unless the other person has given verbal consent | Initiate physical contact or simulate physical contact without consent
|
||||
Disengage and find another activity if someone did not invite you and is not engaging with you | Violate personal space by continuing your physical presence into private spaces without consent
|
||||
Exercise the right to talk about your own identity if you want to, or not if you don’t want to | Deliberately “out” any aspect of a person’s identity without their consent
|
||||
Use the pronouns people have specified for themselves | Purposely misgender someone (ie, refusing to use their correct gender pronouns) after they have told you their correct pronouns
|
||||
|
||||
|
||||
## Additional guidelines for online community behavior
|
||||
|
||||
|
||||
Online modes of interaction involve large numbers of people without the helpful presence of gestural, expression, and tonal cues regarding consent. Because of this, respectful and self-aware online conduct is both especially important and difficult. Our community has evolved specific guidelines for online interactions.
|
||||
|
||||
_If someone violates these guidelines, someone from the Moderators group will place them into moderation by changing that person’s posting permission on the relevant list, on the website, or both._
|
||||
|
||||
Our triple notification standard for moderation means a point person from the Moderators group will:
|
||||
|
||||
1. e-mail the person directly with a brief explanation of what was violated,
|
||||
2. send a summary email to the rest of the moderators group,
|
||||
3. if it happened on a public list (vs a website), notify the list that one of our members has been placed into moderation with a brief explanation of what is not tolerated.
|
||||
|
||||
|
||||
If you wish to begin the process of getting out of moderation, respond to the email sent to you from [moderators@publiclab.org](mailto:moderators@publiclab.org). The Moderators group has the option to involve ConductCom.
|
||||
|
||||
|
||||
Do | Don’t
|
||||
-------|--------
|
||||
Stay on topic to make long threads easier to follow |Send spurious one-line responses that effectively "spam" hundreds of people and lower the overall content quality of a conversation. (Exception: expressions of appreciation and encouragement!)
|
||||
Start a new thread to help others follow along. Important if your response starts to significantly diverge from the original topic | Respond with off-topic information making it hard for the large group of readers to follow along
|
||||
Write short and literal subject lines to help the readers of the list manage the volume of communication | Humor and euphemisms in subject lines are easily misunderstood, although enthusiasm is welcome!
|
||||
Mind your tone. We are not having this conversation in person, so it is all the more important to maintain a tone of respect | Write in aggressive tone, disrespectful tone, mocking tone, off-color tone. Note: writing in all caps is regarded as shouting
|
||||
|
||||
## Media Consent
|
||||
|
||||
* ALWAYS check with parents about posting anything with minors.
|
||||
* Never post the names of minors in conjunction with their photo.
|
||||
* During multi-day events like Barnraisings most people will have signed media releases. Those who haven’t will be responsible for placing stickers on their nametags, and/or raising their hands in the moment to alert photographers to move them out of frame.
|
||||
* For events where people have not signed blanket media release forms, the photographer is responsible for letting the room know that you are taking photos that will be posted online. Pay special attention to the presence of minors and their parent's wishes.
|
||||
|
||||
|
||||
## Addendum for all staff
|
||||
|
||||
Staff are bound by their Employment Handbook, you must reference it. Additionally:
|
||||
|
||||
* Direct problems that come up among community members to the Conduct Committee.
|
||||
* When organizing events, circulate access information regarding wheelchair-accessible ADA bathrooms, non-gendered bathrooms, the presence of stairs or curb ramps in the parking lot, et cetera.
|
||||
* During events that you are attending in person, solve accessibility issues by making sure attendees know where bathrooms are located and can access them by wheelchair without being obstructed by things like chairs, kites, contraptions, or cords.
|
||||
* Watch for people feeling left out and include them.
|
||||
@@ -175,6 +175,7 @@ There are four events in all:
|
||||
* `UI.onComplete(options.step)` must be emitted whenever the output of a draw call
|
||||
is ready. An argument, that is the DataURL of the output image must be passed in.
|
||||
* `UI.onRemove(options.step)` is emitted automatically and the module should not emit it.
|
||||
* `UI.notify(msg,id)` must be emmited when a notification has to be produced.
|
||||
|
||||
### Name and description
|
||||
|
||||
|
||||
10
Gruntfile.js
10
Gruntfile.js
@@ -24,6 +24,10 @@ module.exports = function(grunt) {
|
||||
dist: {
|
||||
src: ["src/ImageSequencer.js"],
|
||||
dest: "dist/image-sequencer.js"
|
||||
},
|
||||
js: {
|
||||
src: ["examples/demo.js"],
|
||||
dest: "dist/image-sequencer-ui.js"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -31,6 +35,10 @@ module.exports = function(grunt) {
|
||||
dist: {
|
||||
src: ["./dist/image-sequencer.js"],
|
||||
dest: "./dist/image-sequencer.min.js"
|
||||
},
|
||||
js: {
|
||||
src: ['dist/image-sequencer-ui.js'],
|
||||
dest: 'dist/image-sequencer-ui.min.js'
|
||||
}
|
||||
},
|
||||
browserSync: {
|
||||
@@ -46,5 +54,5 @@ module.exports = function(grunt) {
|
||||
/* Default (development): Watch files and build on change. */
|
||||
grunt.registerTask("default", ["watch"]);
|
||||
grunt.registerTask("build", ["browserify:dist", "uglify:dist"]);
|
||||
grunt.registerTask("serve", ["browserify:dist", "uglify:dist", "browserSync", "watch"]);
|
||||
grunt.registerTask("serve", ["browserify:dist","browserify:js","uglify:dist","uglify:js","browserSync", "watch"]);
|
||||
};
|
||||
|
||||
@@ -549,6 +549,10 @@ for a module. This can be used, for instance, to update the DIV with the new ima
|
||||
and remove the loading GIF generated above.
|
||||
* `onRemove` : This event is triggered when a module is removed. This can be used,
|
||||
for instance, to remove the DIV generated above.
|
||||
* `notify` : This event is triggered whenever we need to shoot a notification to the
|
||||
user-interface.For example when the step is not available, we can shoot a notification,
|
||||
by sending appropriate message.For HTML UI it adds a DOM node to the browser, for CLI
|
||||
and node , it logs the notification output to the respective console.
|
||||
|
||||
How to define these functions:
|
||||
|
||||
@@ -557,7 +561,8 @@ sequencer.setUI({
|
||||
onSetup: function(step) {},
|
||||
onDraw: function(step) {},
|
||||
onComplete: function(step) {},
|
||||
onRemove: function(step) {}
|
||||
onRemove: function(step) {},
|
||||
notify: function(msg,id) {}
|
||||
});
|
||||
```
|
||||
|
||||
@@ -607,3 +612,5 @@ not specified, the name of a loaded image defaults to a name like "image1",
|
||||
|
||||
Details of all modules can be sought using `sequencer.modulesInfo()`.
|
||||
This method returns an object which defines the name and inputs of the modules. If a module name (hyphenated) is passed in the method, then only the details of that module are returned.
|
||||
|
||||
The `notify` function takes two parameters `msg` and `id`, former being the message to be displayed on console (in case of CLI and node ) and a HTML component(in browser). The id is optional and is useful for HTML interface to give appropriate IDs.
|
||||
896
dist/image-sequencer-ui.js
vendored
Normal file
896
dist/image-sequencer-ui.js
vendored
Normal file
@@ -0,0 +1,896 @@
|
||||
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
||||
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
||||
setupCache = require('./lib/cache.js'),
|
||||
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
||||
urlHash = require('./lib/urlHash.js'),
|
||||
insertPreview = require('./lib/insertPreview.js');
|
||||
|
||||
window.onload = function() {
|
||||
sequencer = ImageSequencer();
|
||||
|
||||
function refreshOptions() {
|
||||
// Load information of all modules (Name, Inputs, Outputs)
|
||||
var modulesInfo = sequencer.modulesInfo();
|
||||
|
||||
var addStepSelect = $("#addStep select");
|
||||
addStepSelect.html("");
|
||||
|
||||
// Add modules to the addStep dropdown
|
||||
for (var m in modulesInfo) {
|
||||
if (modulesInfo[m] && modulesInfo[m].name)
|
||||
addStepSelect.append(
|
||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||
);
|
||||
}
|
||||
// Null option
|
||||
addStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||
}
|
||||
refreshOptions();
|
||||
|
||||
$(window).on('scroll', scrollFunction);
|
||||
|
||||
function scrollFunction() {
|
||||
var shouldDisplay = $('body').scrollTop() > 20 || $(':root').scrollTop() > 20;
|
||||
|
||||
$('#move-up').css({
|
||||
display: shouldDisplay ? 'block' : 'none'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function topFunction() {
|
||||
$('body').animate({scrollTop: 0});
|
||||
$(':root').animate({scrollTop: 0});
|
||||
}
|
||||
|
||||
$('#move-up').on("click",topFunction);
|
||||
|
||||
|
||||
// UI for each step:
|
||||
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
||||
|
||||
// UI for the overall demo:
|
||||
var ui = defaultHtmlSequencerUi(sequencer);
|
||||
|
||||
// find any `src` parameters in URL hash and attempt to source image from them and run the sequencer
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
sequencer.loadImage(urlHash.getUrlHashParameter('src'), ui.onLoad);
|
||||
} else {
|
||||
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||
}
|
||||
|
||||
var resetSequence = function(){
|
||||
var r=confirm("Do you want to reset the sequence?");
|
||||
if (r)
|
||||
window.location = "/";
|
||||
}
|
||||
|
||||
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||
$("#addStep #add-step-btn").on("click", ui.addStepUi);
|
||||
$("#resetButton").on("click",resetSequence);
|
||||
|
||||
//Module button radio selection
|
||||
$('.radio-group .radio').on("click", function() {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
//$("#addStep option[value=" + newStep + "]").attr('selected', 'selected');
|
||||
$("#addStep select").val(newStep);
|
||||
ui.selectNewStepUi();
|
||||
ui.addStepUi();
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
|
||||
$('#download-btn').click(function() {
|
||||
$('.step-thumbnail:last()').trigger("click");
|
||||
return false;
|
||||
});
|
||||
|
||||
function displayMessageOnSaveSequence(){
|
||||
$(".savesequencemsg").fadeIn();
|
||||
setTimeout(function() {
|
||||
$(".savesequencemsg").fadeOut();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||
$('#save-seq').click(() => {
|
||||
var result = window.prompt("Please give a name to your sequence... (Saved sequence will only be available in this browser).");
|
||||
if(result){
|
||||
result = result + " (local)";
|
||||
sequencer.saveSequence(result, sequencer.toString());
|
||||
sequencer.loadModules();
|
||||
displayMessageOnSaveSequence();
|
||||
refreshOptions();
|
||||
}
|
||||
});
|
||||
|
||||
var isWorkingOnGifGeneration = false;
|
||||
|
||||
$('.js-view-as-gif').on('click', function(event) {
|
||||
// Prevent user from triggering generation multiple times
|
||||
if (isWorkingOnGifGeneration) return;
|
||||
|
||||
isWorkingOnGifGeneration = true;
|
||||
|
||||
var button = event.target;
|
||||
button.disabled = true;
|
||||
|
||||
|
||||
try {
|
||||
// Select all images from previous steps
|
||||
var imgs = document.getElementsByClassName("step-thumbnail");
|
||||
|
||||
var imgSrcs = [];
|
||||
|
||||
for (var i = 0; i < imgs.length; i++) {
|
||||
imgSrcs.push(imgs[i].src);
|
||||
}
|
||||
|
||||
var options = {
|
||||
'gifWidth': imgs[0].width,
|
||||
'gifHeight': imgs[0].height,
|
||||
'images': imgSrcs,
|
||||
'frameDuration': 7,
|
||||
}
|
||||
|
||||
gifshot.createGIF(options, function(obj) {
|
||||
if (!obj.error) {
|
||||
// Final gif encoded with base64 format
|
||||
var image = obj.image;
|
||||
var animatedImage = document.createElement('img');
|
||||
|
||||
animatedImage.id = "gif_element";
|
||||
animatedImage.src = image;
|
||||
|
||||
|
||||
var modal = $('#js-download-gif-modal');
|
||||
|
||||
$("#js-download-as-gif-button").one("click", function() {
|
||||
// Trigger download
|
||||
download(image, "index.gif", "image/gif");
|
||||
|
||||
// Close modal
|
||||
modal.modal('hide');
|
||||
})
|
||||
|
||||
var gifContainer = document.getElementById("js-download-modal-gif-container");
|
||||
|
||||
// Clear previous results
|
||||
gifContainer.innerHTML = '';
|
||||
|
||||
// Insert image
|
||||
gifContainer.appendChild(animatedImage);
|
||||
|
||||
|
||||
// Open modal
|
||||
modal.modal();
|
||||
|
||||
button.disabled = false;
|
||||
isWorkingOnGifGeneration = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
button.disabled = false;
|
||||
isWorkingOnGifGeneration = false;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// image selection and drag/drop handling from examples/lib/imageSelection.js
|
||||
sequencer.setInputStep({
|
||||
dropZoneSelector: "#dropzone",
|
||||
fileInputSelector: "#fileInput",
|
||||
takePhotoSelector: "#take-photo",
|
||||
onLoad: function onFileReaderLoad(progress) {
|
||||
var reader = progress.target;
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
var util=IntermediateHtmlStepUi(sequencer);
|
||||
step.output.src = reader.result;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = reader.result;
|
||||
insertPreview.updatePreviews(reader.result,'addStep');
|
||||
insertPreview.updatePreviews(sequencer.images.image1.steps[0].options.step.imgElement.src,'insertStep');
|
||||
},
|
||||
onTakePhoto: function (url) {
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
step.output.src = url;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = url;
|
||||
}
|
||||
});
|
||||
|
||||
setupCache();
|
||||
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'addStep');
|
||||
} else {
|
||||
insertPreview.updatePreviews("images/tulips.png",'addStep');
|
||||
}
|
||||
};
|
||||
},{"./lib/cache.js":2,"./lib/defaultHtmlSequencerUi.js":3,"./lib/defaultHtmlStepUi.js":4,"./lib/insertPreview.js":5,"./lib/urlHash.js":7}],2:[function(require,module,exports){
|
||||
var setupCache = function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
||||
.then(function(registration) {
|
||||
const installingWorker = registration.installing;
|
||||
installingWorker.onstatechange = () => {
|
||||
console.log(installingWorker)
|
||||
if (installingWorker.state === 'installed') {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
console.log('Registration successful, scope is:', registration.scope);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log('Service worker registration failed, error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
$("#clear-cache").append(" " + cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$("#clear-cache").click(function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = setupCache;
|
||||
},{}],3:[function(require,module,exports){
|
||||
var urlHash = require('./urlHash.js');
|
||||
function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
options = options || {};
|
||||
var addStepSel = options.addStepSel = options.addStepSel || "#addStep";
|
||||
var removeStepSel = options.removeStepSel = options.removeStepSel || "button.remove";
|
||||
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||
|
||||
function onLoad() {
|
||||
importStepsFromUrlHash();
|
||||
if (!$('#selectStep').val())
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", true);
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
// look up needed steps from Url Hash:
|
||||
function importStepsFromUrlHash() {
|
||||
var hash = urlHash.getUrlHashParameter("steps");
|
||||
|
||||
if (hash) {
|
||||
_sequencer.importString(hash);
|
||||
_sequencer.run({ index: 0 });
|
||||
}
|
||||
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||
}
|
||||
|
||||
function selectNewStepUi() {
|
||||
var m = $(addStepSel + " select").val();
|
||||
$(addStepSel + " .info").html(_sequencer.modulesInfo(m).description);
|
||||
$(addStepSel + " #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
|
||||
function removeStepUi() {
|
||||
var index = $(removeStepSel).index(this) + 1;
|
||||
sequencer.removeSteps(index).run({ index: index - 1 });
|
||||
// remove from URL hash too
|
||||
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||
//disable save-sequence button if all steps are removed
|
||||
handleSaveSequence();
|
||||
}
|
||||
|
||||
function addStepUi() {
|
||||
if ($(addStepSel + " select").val() == "none") return;
|
||||
|
||||
var newStepName = $(addStepSel + " select").val();
|
||||
|
||||
/*
|
||||
* after adding the step we run the sequencer from defined step
|
||||
* and since loadImage is not a part of the drawarray the step lies at current
|
||||
* length - 2 of the drawarray
|
||||
*/
|
||||
var sequenceLength = 1;
|
||||
if (sequencer.sequences[newStepName]) {
|
||||
sequenceLength = sequencer.sequences[newStepName].length;
|
||||
} else if (sequencer.modules[newStepName][1]["length"]) {
|
||||
sequenceLength = sequencer.modules[newStepName][1]["length"];
|
||||
}
|
||||
_sequencer
|
||||
.addSteps(newStepName, options)
|
||||
.run({ index: _sequencer.images.image1.steps.length - sequenceLength - 1 });
|
||||
$(addStepSel + " .info").html("Select a new module to add to your sequence.");
|
||||
$(addStepSel + " select").val("none");
|
||||
|
||||
//enable save-sequence button if disabled initially
|
||||
handleSaveSequence();
|
||||
|
||||
// add to URL hash too
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
}
|
||||
|
||||
function handleSaveSequence(){
|
||||
var stepCount=sequencer.images.image1.steps.length;
|
||||
if(stepCount<2)
|
||||
$(" #save-seq").prop("disabled", true);
|
||||
else
|
||||
$(" #save-seq").prop("disabled", false);
|
||||
}
|
||||
|
||||
return {
|
||||
onLoad: onLoad,
|
||||
importStepsFromUrlHash: importStepsFromUrlHash,
|
||||
selectNewStepUi: selectNewStepUi,
|
||||
removeStepUi: removeStepUi,
|
||||
addStepUi: addStepUi
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultHtmlSequencerUi;
|
||||
|
||||
|
||||
},{"./urlHash.js":7}],4:[function(require,module,exports){
|
||||
// Set the UI in sequencer. This Will generate HTML based on
|
||||
// Image Sequencer events :
|
||||
// onSetup : Called every time a step is added
|
||||
// onDraw : Called every time a step starts draw
|
||||
// onComplete : Called every time a step finishes drawing
|
||||
// onRemove : Called everytime a step is removed
|
||||
// The variable 'step' stores useful data like input and
|
||||
// output values, step information.
|
||||
// See documetation for more details.
|
||||
|
||||
var intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js');
|
||||
var urlHash = require('./urlHash.js');
|
||||
|
||||
function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
options = options || {};
|
||||
var stepsEl = options.stepsEl || document.querySelector("#steps");
|
||||
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||
|
||||
function onSetup(step, stepOptions) {
|
||||
if (step.options && step.options.description)
|
||||
step.description = step.options.description;
|
||||
|
||||
step.ui =
|
||||
'\
|
||||
<div class="container">\
|
||||
<div class="row step">\
|
||||
<form class="input-form">\
|
||||
<div class="col-md-4 details">\
|
||||
<h3>\
|
||||
<span class = "toggle">' +step.name + ' <i class="fa fa-caret-up toggleIcon" aria-hidden="true"></i></span>' +
|
||||
'<span class="load-spin" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></span>' +
|
||||
'</h3><div class="cal"><p><i>"'+
|
||||
(step.description || "") +
|
||||
'</i></p></div>\
|
||||
</div>\
|
||||
</form>\
|
||||
<div class="col-md-8 cal">\
|
||||
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
||||
<a><img alt="" style="max-width=100%" class="img-thumbnail step-thumbnail"/></a>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var tools =
|
||||
'<div class="cal"><div class="tools btn-group">\
|
||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
<button class="btn insert-step" style="margin-left:10px;border-radius:6px;background-color:#fff;border:solid #bababa 1.1px;" >\
|
||||
<i class="fa fa-plus"></i> Add\
|
||||
</button>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var util = intermediateHtmlStepUi(_sequencer, step);
|
||||
|
||||
var parser = new DOMParser();
|
||||
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||
step.ui = step.ui.querySelector("div.container");
|
||||
step.linkElements = step.ui.querySelectorAll("a");
|
||||
step.imgElement = step.ui.querySelector("a img");
|
||||
|
||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||
var merged = Object.assign(inputs, outputs); // combine outputs w inputs
|
||||
|
||||
for (var paramName in merged) {
|
||||
var isInput = inputs.hasOwnProperty(paramName);
|
||||
var html = "";
|
||||
var inputDesc = isInput ? inputs[paramName] : {};
|
||||
if (!isInput) {
|
||||
html += '<span class="output"></span>';
|
||||
} else if (inputDesc.type.toLowerCase() == "select") {
|
||||
html += '<select class="form-control target" name="' + paramName + '">';
|
||||
for (var option in inputDesc.values) {
|
||||
html += "<option>" + inputDesc.values[option] + "</option>";
|
||||
}
|
||||
html += "</select>";
|
||||
} else {
|
||||
let paramVal = step.options[paramName] || inputDesc.default;
|
||||
html =
|
||||
'<input class="form-control target" type="' +
|
||||
inputDesc.type +
|
||||
'" name="' +
|
||||
paramName +
|
||||
'" value="' +
|
||||
paramVal +
|
||||
'" placeholder ="' +
|
||||
(inputDesc.placeholder || "");
|
||||
|
||||
if (inputDesc.type.toLowerCase() == "range") {
|
||||
html +=
|
||||
'"min="' +
|
||||
inputDesc.min +
|
||||
'"max="' +
|
||||
inputDesc.max +
|
||||
'"step="' +
|
||||
inputDesc.step + '">' + '<span>' + paramVal + '</span>';
|
||||
|
||||
}
|
||||
else html += '">';
|
||||
}
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.className = "row";
|
||||
div.setAttribute("name", paramName);
|
||||
var description = inputs[paramName].desc || paramName;
|
||||
div.innerHTML =
|
||||
"<div class='det cal'>\
|
||||
<label for='" +
|
||||
paramName +
|
||||
"'>" +
|
||||
description +
|
||||
"</label>\
|
||||
" +
|
||||
html +
|
||||
"\
|
||||
</div>";
|
||||
step.ui.querySelector("div.details").appendChild(div);
|
||||
}
|
||||
|
||||
$(step.ui.querySelector("div.details")).append(
|
||||
'<div class="cal"><p><button type="submit" class="btn btn-default btn-save" disabled = "true" >Apply</button><span> Press apply to see changes</span></p></div>'
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (step.name != "load-image") {
|
||||
step.ui
|
||||
.querySelector("div.details")
|
||||
.appendChild(
|
||||
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||
);
|
||||
$(step.ui.querySelectorAll(".remove")).on('click', function() {notify('Step Removed','remove-notification')});
|
||||
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||
|
||||
// Insert the step's UI in the right place
|
||||
if (stepOptions.index == _sequencer.images.image1.steps.length) {
|
||||
stepsEl.appendChild(step.ui);
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
if($("#steps .container:nth-last-child(2)"))
|
||||
$("#steps .container:nth-last-child(2) .insert-step").prop('disabled',false);
|
||||
} else {
|
||||
stepsEl.insertBefore(step.ui, $(stepsEl).children()[stepOptions.index]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$("#load-image").append(step.ui);
|
||||
}
|
||||
$(step.ui.querySelector(".toggle")).on("click", () => {
|
||||
$(step.ui.querySelector('.toggleIcon')).toggleClass('fa-caret-up').toggleClass('fa-caret-down');
|
||||
$(step.ui.querySelectorAll(".cal")).toggleClass("collapse");
|
||||
});
|
||||
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
if (optionsChanged){
|
||||
$(step.ui.querySelector("div.details"))
|
||||
.find("input,select")
|
||||
.each(function(i, input) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false);
|
||||
step.options[$(input).attr("name")] = $(input).val();
|
||||
});
|
||||
_sequencer.run({ index: step.index - 1 });
|
||||
|
||||
// modify the url hash
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
// disable the save button
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', true);
|
||||
optionsChanged = false;
|
||||
changedInputs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function handleInputValueChange(currentValue, initValue, hasChangedBefore) {
|
||||
var inputChanged = !(isNaN(initValue) || isNaN(currentValue) ? currentValue === initValue : currentValue - initValue === 0);
|
||||
changedInputs += hasChangedBefore ? inputChanged ? 0 : -1 : inputChanged ? 1 : 0;
|
||||
optionsChanged = changedInputs > 0;
|
||||
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', !optionsChanged);
|
||||
return inputChanged;
|
||||
}
|
||||
|
||||
var
|
||||
changedInputs = 0,
|
||||
optionsChanged = false;
|
||||
$(step.ui.querySelector('.input-form')).on('submit', saveOptions);
|
||||
$(step.ui.querySelectorAll('.target')).each(function(i, input) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false)
|
||||
.on('input', function() {
|
||||
$(this)
|
||||
.focus()
|
||||
.data('hasChangedBefore',
|
||||
handleInputValueChange(
|
||||
$(this).val(),
|
||||
$(this).data('initValue'),
|
||||
$(this).data('hasChangedBefore')
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
$('input[type="range"]').on('input', function() {
|
||||
$(this).next().html($(this).val());
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function onDraw(step) {
|
||||
$(step.ui.querySelector(".load")).show();
|
||||
$(step.ui.querySelector("img")).hide();
|
||||
if( $(step.ui.querySelector(".toggleIcon")).hasClass("fa-caret-down") )
|
||||
{
|
||||
$(step.ui.querySelector(".load-spin")).show();
|
||||
}
|
||||
}
|
||||
|
||||
function onComplete(step) {
|
||||
$(step.ui.querySelector(".load")).hide();
|
||||
$(step.ui.querySelector("img")).show();
|
||||
$(step.ui.querySelector(".load-spin")).hide();
|
||||
|
||||
step.imgElement.src = step.output;
|
||||
var imgthumbnail = step.ui.querySelector(".img-thumbnail");
|
||||
for (let index = 0; index < step.linkElements.length; index++) {
|
||||
if (step.linkElements[index].contains(imgthumbnail))
|
||||
step.linkElements[index].href = step.output;
|
||||
}
|
||||
|
||||
// TODO: use a generalized version of this
|
||||
function fileExtension(output) {
|
||||
return output.split("/")[1].split(";")[0];
|
||||
}
|
||||
|
||||
for (let index = 0; index < step.linkElements.length; index++) {
|
||||
step.linkElements[index].download = step.name + "." + fileExtension(step.output);
|
||||
step.linkElements[index].target = "_blank";
|
||||
}
|
||||
|
||||
// fill inputs with stored step options
|
||||
if (_sequencer.modulesInfo().hasOwnProperty(step.name)) {
|
||||
var inputs = _sequencer.modulesInfo(step.name).inputs;
|
||||
var outputs = _sequencer.modulesInfo(step.name).outputs;
|
||||
for (var i in inputs) {
|
||||
if (step.options[i] !== undefined) {
|
||||
if (inputs[i].type.toLowerCase() === "input")
|
||||
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||
.val(step.options[i])
|
||||
.data('initValue', step.options[i]);
|
||||
if (inputs[i].type.toLowerCase() === "select")
|
||||
$(step.ui.querySelector('div[name="' + i + '"] select'))
|
||||
.val(step.options[i])
|
||||
.data('initValue', step.options[i]);
|
||||
}
|
||||
}
|
||||
for (var i in outputs) {
|
||||
if (step[i] !== undefined)
|
||||
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||
.val(step[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onRemove(step) {
|
||||
step.ui.remove();
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
$('div[class^=imgareaselect-]').remove();
|
||||
}
|
||||
|
||||
function getPreview() {
|
||||
return step.imgElement;
|
||||
}
|
||||
|
||||
function notify(msg,id){
|
||||
if ($('#'+id).length == 0) {
|
||||
var notification = document.createElement('span');
|
||||
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> ' + msg ;
|
||||
notification.id = id;
|
||||
notification.classList.add("notification");
|
||||
|
||||
$('body').append(notification);
|
||||
}
|
||||
|
||||
$('#'+id).fadeIn(500).delay(200).fadeOut(500);
|
||||
}
|
||||
|
||||
return {
|
||||
getPreview: getPreview,
|
||||
onSetup: onSetup,
|
||||
onComplete: onComplete,
|
||||
onRemove: onRemove,
|
||||
onDraw: onDraw,
|
||||
notify: notify
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof window === "undefined"){
|
||||
module.exports={
|
||||
DefaultHtmlStepUi: DefaultHtmlStepUi
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultHtmlStepUi;
|
||||
|
||||
|
||||
},{"./intermediateHtmlStepUi.js":6,"./urlHash.js":7}],5:[function(require,module,exports){
|
||||
function generatePreview(previewStepName, customValues, path, selector) {
|
||||
|
||||
var previewSequencer = ImageSequencer();
|
||||
function insertPreview(src) {
|
||||
var img = document.createElement('img');
|
||||
img.classList.add('img-thumbnail')
|
||||
img.classList.add('no-border');
|
||||
img.src = src;
|
||||
$(img).css("max-width", "200%");
|
||||
$(img).css("transform", "translateX(-20%)");
|
||||
var stepDiv = $('#'+selector+' .row').find('div').each(function() {
|
||||
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||
$(this).find('div').append(img);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadPreview() {
|
||||
previewSequencer = previewSequencer.addSteps('resize', { resize: "40%" });
|
||||
if (previewStepName === "crop") {
|
||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
||||
}
|
||||
else {
|
||||
previewSequencer.addSteps(previewStepName, { [previewStepName]: customValues }).run(insertPreview);
|
||||
}
|
||||
}
|
||||
previewSequencer.loadImage(path, loadPreview);
|
||||
}
|
||||
|
||||
function updatePreviews(src, selector) {
|
||||
$('#'+selector+' img').remove();
|
||||
|
||||
var previewSequencerSteps = {
|
||||
"brightness": "20",
|
||||
"saturation": "5",
|
||||
"rotate": 90,
|
||||
"contrast": 90,
|
||||
"crop": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": "(50%)",
|
||||
"h": "(50%)",
|
||||
"noUI": true
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(previewSequencerSteps).forEach(function (step, index) {
|
||||
generatePreview(step, Object.values(previewSequencerSteps)[index], src, selector);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generatePreview : generatePreview,
|
||||
updatePreviews : updatePreviews
|
||||
}
|
||||
},{}],6:[function(require,module,exports){
|
||||
var urlHash = require('./urlHash.js');
|
||||
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
function stepUI() {
|
||||
return '<div class="row insertDiv">\
|
||||
<div class="col-md-6 col-md-offset-2" style="margin-top:5%">\
|
||||
<section id="insertStep" class="panel panel-primary">\
|
||||
<div class="form-inline">\
|
||||
<div class="panel-body">\
|
||||
<p class="info">Select a new module to add to your sequence.</p>\
|
||||
<div class="row center-align radio-group">\
|
||||
<div>\
|
||||
<div class="radio" data-value="brightness">\
|
||||
<i class="fa fa-sun-o fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Brightness</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<div class="radio" data-value="contrast">\
|
||||
<i class="fa fa-adjust fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Contrast</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<div class="radio" data-value="saturation">\
|
||||
<i class="fa fa-tint fa-4x i-over i-small"></i>\
|
||||
</div>\
|
||||
<p>Saturation</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<div class="radio" data-value="rotate">\
|
||||
<i class="fa fa-rotate-right fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Rotate</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<div class="radio" data-value="crop">\
|
||||
<i class="fa fa-crop fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Crop</p>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="center-align">\
|
||||
<select class="form-control input-lg" id="selectStep">\
|
||||
<!-- The default null selection has been appended manually in demo.js\
|
||||
This is because the options in select are overritten when options are appended.-->\
|
||||
</select>\
|
||||
<button class="btn btn-success btn-lg" name="add" id="add-step-btn">Add Step</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</section>\
|
||||
</div>';
|
||||
}
|
||||
|
||||
|
||||
function selectNewStepUi() {
|
||||
var m = $("#insertStep select").val();
|
||||
$("#insertStep .info").html(_sequencer.modulesInfo(m).description);
|
||||
$("#insertStep #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
insertStep = function (id) {
|
||||
var modulesInfo = _sequencer.modulesInfo();
|
||||
var parser = new DOMParser();
|
||||
var addStepUI = stepUI();
|
||||
addStepUI = parser.parseFromString(addStepUI, "text/html").querySelector("div")
|
||||
step.ui
|
||||
.querySelector("div.step")
|
||||
.insertAdjacentElement('afterend',
|
||||
addStepUI
|
||||
);
|
||||
updatePreviews(step.output,'insertStep');
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
insertStepSelect.html("");
|
||||
// Add modules to the insertStep dropdown
|
||||
for (var m in modulesInfo) {
|
||||
if (modulesInfo[m] !== undefined)
|
||||
insertStepSelect.append(
|
||||
'<option value="' + m + '">' + modulesInfo[m].name + "</option>"
|
||||
);
|
||||
}
|
||||
|
||||
$('#insertStep #add-step-btn').prop('disabled', true);
|
||||
|
||||
insertStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||
$('#insertStep .radio-group .radio').on("click", function () {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
insertStepSelect.val(newStep);
|
||||
selectNewStepUi();
|
||||
insert(id);
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
$(step.ui.querySelector("#insertStep select")).on('change', selectNewStepUi);
|
||||
$(step.ui.querySelector("#insertStep #add-step-btn")).on('click', function () { insert(id) });
|
||||
}
|
||||
|
||||
function insert(id) {
|
||||
|
||||
options = options || {};
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
if (insertStepSelect.val() == "none") return;
|
||||
|
||||
var newStepName = insertStepSelect.val()
|
||||
$('div .insertDiv').remove();
|
||||
var sequenceLength = 1;
|
||||
if (sequencer.sequences[newStepName]) {
|
||||
sequenceLength = sequencer.sequences[newStepName].length;
|
||||
} else if (sequencer.modules[newStepName][1]["length"]) {
|
||||
sequenceLength = sequencer.modules[newStepName][1]["length"];
|
||||
}
|
||||
_sequencer
|
||||
.insertSteps(id + 1, newStepName).run({ index: id });
|
||||
|
||||
// add to URL hash too
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
insertStep
|
||||
}
|
||||
}
|
||||
module.exports = IntermediateHtmlStepUi;
|
||||
|
||||
|
||||
},{"./urlHash.js":7}],7:[function(require,module,exports){
|
||||
function getUrlHashParameter(param) {
|
||||
|
||||
var params = getUrlHashParameters();
|
||||
return params[param];
|
||||
|
||||
}
|
||||
|
||||
function getUrlHashParameters() {
|
||||
|
||||
var sPageURL = window.location.hash;
|
||||
if (sPageURL) sPageURL = sPageURL.split('#')[1];
|
||||
var pairs = sPageURL.split('&');
|
||||
var object = {};
|
||||
pairs.forEach(function(pair, i) {
|
||||
pair = pair.split('=');
|
||||
if (pair[0] != '') object[pair[0]] = pair[1];
|
||||
});
|
||||
return object;
|
||||
}
|
||||
|
||||
// accepts an object like { paramName: value, paramName1: value }
|
||||
// and transforms to: url.com#paramName=value¶mName1=value
|
||||
function setUrlHashParameters(params) {
|
||||
|
||||
var keys = Object.keys(params);
|
||||
var values = Object.values(params);
|
||||
var pairs = [];
|
||||
keys.forEach(function(key, i) {
|
||||
if (key != '') pairs.push(keys[i] + '=' + values[i]);
|
||||
});
|
||||
var hash = pairs.join('&');
|
||||
window.location.hash = hash;
|
||||
|
||||
}
|
||||
|
||||
function setUrlHashParameter(param, value) {
|
||||
|
||||
var params = getUrlHashParameters();
|
||||
params[param] = value;
|
||||
setUrlHashParameters(params);
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getUrlHashParameter: getUrlHashParameter,
|
||||
setUrlHashParameter: setUrlHashParameter,
|
||||
getUrlHashParameters: getUrlHashParameters,
|
||||
setUrlHashParameters: setUrlHashParameters
|
||||
}
|
||||
|
||||
},{}]},{},[1]);
|
||||
5
dist/image-sequencer-ui.min.js
vendored
Normal file
5
dist/image-sequencer-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
823
dist/image-sequencer.js
vendored
823
dist/image-sequencer.js
vendored
File diff suppressed because it is too large
Load Diff
6
dist/image-sequencer.min.js
vendored
6
dist/image-sequencer.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -42,11 +42,11 @@ h1 {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
.form-control[type="range"] {
|
||||
padding: 0px 0px;
|
||||
}
|
||||
|
||||
#dropzone {
|
||||
.dropzone {
|
||||
padding: 30px;
|
||||
margin: 0 20% 30px;
|
||||
border: 4px dashed #ccc;
|
||||
@@ -59,7 +59,7 @@ h1 {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
#dropzone input {
|
||||
.dropzone input {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@@ -100,6 +100,11 @@ h1 {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.load-spin{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
#addStep {
|
||||
max-width: 500px;
|
||||
margin: 20px auto;
|
||||
@@ -128,8 +133,8 @@ h1 {
|
||||
}
|
||||
#save-seq {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
min-width: 250px;
|
||||
margin: 0px 10px 0px 0px;
|
||||
width: 250px;
|
||||
}
|
||||
.info {
|
||||
padding: 8px;
|
||||
@@ -137,8 +142,8 @@ h1 {
|
||||
}
|
||||
#gif {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
min-width: 250px;
|
||||
margin: 0px 0px 0px 10px;
|
||||
width: 250px;
|
||||
}
|
||||
#dwnld {
|
||||
max-width: 500px;
|
||||
@@ -153,25 +158,19 @@ h1 {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.move-up {
|
||||
#move-up {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 40px;
|
||||
z-index: 3;
|
||||
z-index: 550;
|
||||
display: none;
|
||||
z-index:1000;
|
||||
}
|
||||
.move-up button {
|
||||
background:transparent;
|
||||
border:none;
|
||||
}
|
||||
.move-up button:active:hover {
|
||||
padding-right:4px !important;
|
||||
margin-right:2px;
|
||||
}
|
||||
.move-up i {
|
||||
|
||||
#move-up i {
|
||||
font-size:60px;
|
||||
opacity:0.5;
|
||||
opacity:0.7;
|
||||
color:#BABABA;
|
||||
}
|
||||
|
||||
@@ -199,24 +198,35 @@ h1 {
|
||||
|
||||
.radio-group {
|
||||
margin-bottom: 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#stepRemovedNotification {
|
||||
.no-border {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.savesequencemsg{
|
||||
display: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.notification {
|
||||
background-color: #808b96;
|
||||
padding:4px;
|
||||
color:white;
|
||||
border-radius:3px;
|
||||
font-size:2rem;
|
||||
position:fixed;
|
||||
bottom:8px;
|
||||
left:45%;
|
||||
bottom:2px;
|
||||
left:50%;
|
||||
min-width:14rem;
|
||||
text-align:center;
|
||||
display:none;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.no-border {
|
||||
border: 0px;
|
||||
#resetButton {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.i-over {
|
||||
@@ -230,3 +240,13 @@ h1 {
|
||||
.i-small {
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
@media all and (max-width: 767px) {
|
||||
.center-align {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
a.name-header{
|
||||
text-decoration: none;
|
||||
color: #445;
|
||||
}
|
||||
|
||||
159
examples/demo.js
159
examples/demo.js
@@ -1,41 +1,15 @@
|
||||
var defaultHtmlSequencerUi = require('./lib/defaultHtmlSequencerUi.js'),
|
||||
setupCache = require('./lib/cache.js'),
|
||||
DefaultHtmlStepUi = require('./lib/defaultHtmlStepUi.js'),
|
||||
urlHash = require('./lib/urlHash.js'),
|
||||
insertPreview = require('./lib/insertPreview.js');
|
||||
|
||||
window.onload = function() {
|
||||
function generatePreview(previewStepName, customValues, path) {
|
||||
var previewSequencer = ImageSequencer();
|
||||
|
||||
function insertPreview(src) {
|
||||
var img = document.createElement('img');
|
||||
img.classList.add('img-thumbnail')
|
||||
img.classList.add('no-border');
|
||||
img.src = src;
|
||||
$(img).css("max-width", "200%");
|
||||
$(img).css("transform", "translateX(-20%)");
|
||||
var stepDiv = $('#addStep .row').find('div').each(function() {
|
||||
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||
$(this).find('div').append(img);
|
||||
}
|
||||
});
|
||||
}
|
||||
function loadPreview() {
|
||||
previewSequencer = previewSequencer.addSteps('resize', { resize: "40%" });
|
||||
|
||||
if (previewStepName === "crop") {
|
||||
console.log(customValues);
|
||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
||||
}
|
||||
else {
|
||||
previewSequencer.addSteps(previewStepName, { [previewStepName]: customValues }).run(insertPreview);
|
||||
}
|
||||
}
|
||||
previewSequencer.loadImage(path, loadPreview);
|
||||
}
|
||||
|
||||
|
||||
sequencer = ImageSequencer();
|
||||
|
||||
function refreshOptions() {
|
||||
// Load information of all modules (Name, Inputs, Outputs)
|
||||
var modulesInfo = sequencer.modulesInfo();
|
||||
console.log(modulesInfo)
|
||||
|
||||
var addStepSelect = $("#addStep select");
|
||||
addStepSelect.html("");
|
||||
@@ -52,28 +26,53 @@ window.onload = function() {
|
||||
}
|
||||
refreshOptions();
|
||||
|
||||
$(window).on('scroll', scrollFunction);
|
||||
|
||||
function scrollFunction() {
|
||||
var shouldDisplay = $('body').scrollTop() > 20 || $(':root').scrollTop() > 20;
|
||||
|
||||
$('#move-up').css({
|
||||
display: shouldDisplay ? 'block' : 'none'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function topFunction() {
|
||||
$('body').animate({scrollTop: 0});
|
||||
$(':root').animate({scrollTop: 0});
|
||||
}
|
||||
|
||||
$('#move-up').on("click",topFunction);
|
||||
|
||||
|
||||
// UI for each step:
|
||||
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
||||
|
||||
// UI for the overall demo:
|
||||
var ui = DefaultHtmlSequencerUi(sequencer);
|
||||
var ui = defaultHtmlSequencerUi(sequencer);
|
||||
|
||||
// find any `src` parameters in URL hash and attempt to source image from them and run the sequencer
|
||||
if (getUrlHashParameter('src')) {
|
||||
sequencer.loadImage(getUrlHashParameter('src'), ui.onLoad);
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
sequencer.loadImage(urlHash.getUrlHashParameter('src'), ui.onLoad);
|
||||
} else {
|
||||
sequencer.loadImage("images/tulips.png", ui.onLoad);
|
||||
}
|
||||
|
||||
var resetSequence = function(){
|
||||
var r=confirm("Do you want to reset the sequence?");
|
||||
if (r)
|
||||
window.location = "/";
|
||||
}
|
||||
|
||||
$("#addStep select").on("change", ui.selectNewStepUi);
|
||||
$("#addStep #add-step-btn").on("click", ui.addStepUi);
|
||||
$("#resetButton").on("click",resetSequence);
|
||||
|
||||
//Module button radio selection
|
||||
$('.radio-group .radio').on("click", function() {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
console.log(newStep);
|
||||
//$("#addStep option[value=" + newStep + "]").attr('selected', 'selected');
|
||||
$("#addStep select").val(newStep);
|
||||
ui.selectNewStepUi();
|
||||
@@ -86,11 +85,23 @@ window.onload = function() {
|
||||
return false;
|
||||
});
|
||||
|
||||
function displayMessageOnSaveSequence(){
|
||||
$(".savesequencemsg").fadeIn();
|
||||
setTimeout(function() {
|
||||
$(".savesequencemsg").fadeOut();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
$('body').on('click', 'button.remove', ui.removeStepUi);
|
||||
$('#save-seq').click(() => {
|
||||
sequencer.saveSequence(window.prompt("Please give a name to your sequence..."), sequencer.toString());
|
||||
sequencer.loadModules();
|
||||
refreshOptions();
|
||||
var result = window.prompt("Please give a name to your sequence... (Saved sequence will only be available in this browser).");
|
||||
if(result){
|
||||
result = result + " (local)";
|
||||
sequencer.saveSequence(result, sequencer.toString());
|
||||
sequencer.loadModules();
|
||||
displayMessageOnSaveSequence();
|
||||
refreshOptions();
|
||||
}
|
||||
});
|
||||
|
||||
var isWorkingOnGifGeneration = false;
|
||||
@@ -175,10 +186,12 @@ window.onload = function() {
|
||||
onLoad: function onFileReaderLoad(progress) {
|
||||
var reader = progress.target;
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
var util=IntermediateHtmlStepUi(sequencer);
|
||||
step.output.src = reader.result;
|
||||
sequencer.run({ index: 0 });
|
||||
step.options.step.imgElement.src = reader.result;
|
||||
updatePreviews(reader.result);
|
||||
insertPreview.updatePreviews(reader.result,'addStep');
|
||||
insertPreview.updatePreviews(sequencer.images.image1.steps[0].options.step.imgElement.src,'insertStep');
|
||||
},
|
||||
onTakePhoto: function (url) {
|
||||
var step = sequencer.images.image1.steps[0];
|
||||
@@ -188,67 +201,11 @@ window.onload = function() {
|
||||
}
|
||||
});
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
||||
.then(function(registration) {
|
||||
const installingWorker = registration.installing;
|
||||
installingWorker.onstatechange = () => {
|
||||
console.log(installingWorker)
|
||||
if (installingWorker.state === 'installed') {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
console.log('Registration successful, scope is:', registration.scope);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log('Service worker registration failed, error:', error);
|
||||
});
|
||||
}
|
||||
setupCache();
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
$("#clear-cache").append(" " + cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$("#clear-cache").click(function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
|
||||
function updatePreviews(src) {
|
||||
$('#addStep img').remove();
|
||||
|
||||
var previewSequencerSteps = {
|
||||
"brightness": "20",
|
||||
"saturation": "5",
|
||||
"rotate": 90,
|
||||
"contrast": 90,
|
||||
"crop": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": "(50%)",
|
||||
"h": "(50%)",
|
||||
"noUI": true
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(previewSequencerSteps).forEach(function(step, index) {
|
||||
generatePreview(step, Object.values(previewSequencerSteps)[index], src);
|
||||
});
|
||||
}
|
||||
|
||||
if (getUrlHashParameter('src')) {
|
||||
updatePreviews(getUrlHashParameter('src'));
|
||||
if (urlHash.getUrlHashParameter('src')) {
|
||||
insertPreview.updatePreviews(urlHash.getUrlHashParameter('src'),'addStep');
|
||||
} else {
|
||||
updatePreviews("images/tulips.png");
|
||||
insertPreview.updatePreviews("images/tulips.png",'addStep');
|
||||
}
|
||||
};
|
||||
};
|
||||
2839
examples/gifshot.js
2839
examples/gifshot.js
File diff suppressed because it is too large
Load Diff
@@ -17,14 +17,10 @@
|
||||
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<script src="../src/ui/prepareDynamic.js"></script>
|
||||
<script src="../dist/image-sequencer.js" charset="utf-8"></script>
|
||||
<script src="lib/urlHash.js" charset="utf-8"></script>
|
||||
<script src="lib/defaultHtmlStepUi.js" charset="utf-8"></script>
|
||||
<script src="lib/defaultHtmlSequencerUi.js" charset="utf-8"></script>
|
||||
<script src="lib/intermediateHtmlStepUi.js" charset="utf-8"></script>
|
||||
<script src="demo.js" charset="utf-8"></script>
|
||||
<script src="../dist/image-sequencer-ui.js" charset="utf-8"></script>
|
||||
<!-- for crop module: -->
|
||||
<script src="../node_modules/imgareaselect/jquery.imgareaselect.dev.js"></script>
|
||||
<script src="gifshot.js" type="text/javascript"></script>
|
||||
<script src="../node_modules/gifshot/dist/gifshot.min.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Download.js for large files -->
|
||||
<script src="../node_modules/downloadjs/download.min.js" type="text/javascript"/>
|
||||
@@ -46,7 +42,7 @@
|
||||
<div class="container-fluid">
|
||||
|
||||
<header class="text-center">
|
||||
<h1>Image Sequencer</h1>
|
||||
<h1><a href="/" target='_blank' class="name-header">Image Sequencer</a></h1>
|
||||
<p>
|
||||
A pure JavaScript sequential image processing system, inspired by storyboards. Instead of modifying the original image, it
|
||||
creates a new image at each step in a sequence.
|
||||
@@ -61,7 +57,7 @@
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div id="dropzone">
|
||||
<div id="dropzone" class="dropzone">
|
||||
<p>
|
||||
<i>Select or drag in an image to start!</i>
|
||||
</p>
|
||||
@@ -80,6 +76,7 @@
|
||||
</section>
|
||||
|
||||
<hr />
|
||||
<p class = "alert alert-success savesequencemsg">Saved Sequence Success. Sequence can be found among other modules.</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<section id="addStep" class="panel panel-primary">
|
||||
@@ -133,8 +130,8 @@
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="row center-align">
|
||||
<button class="btn btn-primary btn-lg" name="save-sequence" id="save-seq">Save Sequence</button>
|
||||
<button class="btn btn-primary btn-lg js-view-as-gif" id="gif">View GIF</button>
|
||||
<button class="btn btn-primary btn-block btn-lg" name="save-sequence" id="save-seq">Save Sequence</button>
|
||||
<button class="btn btn-primary btn-block btn-lg js-view-as-gif" id="gif">View GIF</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -169,6 +166,7 @@
|
||||
<div class="panel-body">
|
||||
<div style="text-align:center;">
|
||||
<button class="btn btn-success btn-lg" id="download-btn" name="download">Download PNG</button>
|
||||
<button id="resetButton" class="btn btn-default btn-lg">Clear All Steps</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -176,14 +174,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="move-up" action="#up">
|
||||
<button><i class="fa fa-arrow-circle-o-up"></i></button>
|
||||
</form>
|
||||
|
||||
<footer>
|
||||
<hr style="margin:20px;"><center><a class="color:grey;" id="clear-cache">Clear offline cache</a></center>
|
||||
</footer>
|
||||
|
||||
<button id="move-up"><i class="fa fa-arrow-circle-o-up"></i></button>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
var sequencer;
|
||||
|
||||
39
examples/lib/cache.js
Normal file
39
examples/lib/cache.js
Normal file
@@ -0,0 +1,39 @@
|
||||
var setupCache = function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('sw.js', { scope: '/examples/' })
|
||||
.then(function(registration) {
|
||||
const installingWorker = registration.installing;
|
||||
installingWorker.onstatechange = () => {
|
||||
console.log(installingWorker)
|
||||
if (installingWorker.state === 'installed') {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
console.log('Registration successful, scope is:', registration.scope);
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log('Service worker registration failed, error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
$("#clear-cache").append(" " + cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$("#clear-cache").click(function() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = setupCache;
|
||||
@@ -1,3 +1,4 @@
|
||||
var urlHash = require('./urlHash.js');
|
||||
function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
options = options || {};
|
||||
@@ -14,13 +15,13 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
|
||||
// look up needed steps from Url Hash:
|
||||
function importStepsFromUrlHash() {
|
||||
var hash = getUrlHashParameter("steps");
|
||||
var hash = urlHash.getUrlHashParameter("steps");
|
||||
|
||||
if (hash) {
|
||||
_sequencer.importString(hash);
|
||||
_sequencer.run({ index: 0 });
|
||||
}
|
||||
setUrlHashParameter("steps", sequencer.toString());
|
||||
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||
}
|
||||
|
||||
function selectNewStepUi() {
|
||||
@@ -33,7 +34,7 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
var index = $(removeStepSel).index(this) + 1;
|
||||
sequencer.removeSteps(index).run({ index: index - 1 });
|
||||
// remove from URL hash too
|
||||
setUrlHashParameter("steps", sequencer.toString());
|
||||
urlHash.setUrlHashParameter("steps", sequencer.toString());
|
||||
//disable save-sequence button if all steps are removed
|
||||
handleSaveSequence();
|
||||
}
|
||||
@@ -57,12 +58,14 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
_sequencer
|
||||
.addSteps(newStepName, options)
|
||||
.run({ index: _sequencer.images.image1.steps.length - sequenceLength - 1 });
|
||||
$(addStepSel + " .info").html("Select a new module to add to your sequence.");
|
||||
$(addStepSel + " select").val("none");
|
||||
|
||||
//enable save-sequence button if disabled initially
|
||||
handleSaveSequence();
|
||||
|
||||
// add to URL hash too
|
||||
setUrlHashParameter("steps", _sequencer.toString());
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
}
|
||||
|
||||
function handleSaveSequence(){
|
||||
@@ -81,3 +84,6 @@ function DefaultHtmlSequencerUi(_sequencer, options) {
|
||||
addStepUi: addStepUi
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultHtmlSequencerUi;
|
||||
|
||||
|
||||
@@ -7,22 +7,16 @@
|
||||
// The variable 'step' stores useful data like input and
|
||||
// output values, step information.
|
||||
// See documetation for more details.
|
||||
function stepRemovedNotify() {
|
||||
if ($('#stepRemovedNotification').length == 0) {
|
||||
var notification = document.createElement('span');
|
||||
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> Step Removed ';
|
||||
notification.id = 'stepRemovedNotification';
|
||||
|
||||
$('body').append(notification);
|
||||
}
|
||||
var intermediateHtmlStepUi = require('./intermediateHtmlStepUi.js');
|
||||
var urlHash = require('./urlHash.js');
|
||||
|
||||
$('#stepRemovedNotification').fadeIn(500).delay(200).fadeOut(500);
|
||||
}
|
||||
function DefaultHtmlStepUi(_sequencer, options) {
|
||||
|
||||
|
||||
options = options || {};
|
||||
var stepsEl = options.stepsEl || document.querySelector("#steps");
|
||||
var selectStepSel = options.selectStepSel = options.selectStepSel || "#selectStep";
|
||||
|
||||
function onSetup(step, stepOptions) {
|
||||
if (step.options && step.options.description)
|
||||
step.description = step.options.description;
|
||||
@@ -31,15 +25,17 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
'\
|
||||
<div class="container">\
|
||||
<div class="row step">\
|
||||
<form class="input-form">\
|
||||
<div class="col-md-4 details">\
|
||||
<h3>' +
|
||||
step.name +
|
||||
"</h3>\
|
||||
<p><i>" +
|
||||
<h3>\
|
||||
<span class = "toggle">' +step.name + ' <i class="fa fa-caret-up toggleIcon" aria-hidden="true"></i></span>' +
|
||||
'<span class="load-spin" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></span>' +
|
||||
'</h3><div class="cal"><p><i>"'+
|
||||
(step.description || "") +
|
||||
'</i></p>\
|
||||
'</i></p></div>\
|
||||
</div>\
|
||||
<div class="col-md-8">\
|
||||
</form>\
|
||||
<div class="col-md-8 cal">\
|
||||
<div class="load" style="display:none;"><i class="fa fa-circle-o-notch fa-spin"></i></div>\
|
||||
<a><img alt="" style="max-width=100%" class="img-thumbnail step-thumbnail"/></a>\
|
||||
</div>\
|
||||
@@ -48,16 +44,17 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
</div>';
|
||||
|
||||
var tools =
|
||||
'<div class="tools btn-group">\
|
||||
<button confirm="Are you sure?" onclick="stepRemovedNotify()" class="remove btn btn btn-default">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
<button class="btn insert-step" style="margin-left:10px;border-radius:6px;background-color:#fff;border:solid #bababa 1.1px;" >\
|
||||
<i class="fa fa-plus"></i> Add\
|
||||
</button>\
|
||||
</div>';
|
||||
'<div class="cal"><div class="tools btn-group">\
|
||||
<button confirm="Are you sure?" class="remove btn btn btn-default">\
|
||||
<i class="fa fa-trash"></i>\
|
||||
</button>\
|
||||
<button class="btn insert-step" style="margin-left:10px;border-radius:6px;background-color:#fff;border:solid #bababa 1.1px;" >\
|
||||
<i class="fa fa-plus"></i> Add\
|
||||
</button>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
var util = IntermediateHtmlStepUi(_sequencer, step);
|
||||
var util = intermediateHtmlStepUi(_sequencer, step);
|
||||
|
||||
var parser = new DOMParser();
|
||||
step.ui = parser.parseFromString(step.ui, "text/html");
|
||||
@@ -112,8 +109,7 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
div.setAttribute("name", paramName);
|
||||
var description = inputs[paramName].desc || paramName;
|
||||
div.innerHTML =
|
||||
"<div class='det'>\
|
||||
<form class='input-form'>\
|
||||
"<div class='det cal'>\
|
||||
<label for='" +
|
||||
paramName +
|
||||
"'>" +
|
||||
@@ -122,44 +118,15 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
" +
|
||||
html +
|
||||
"\
|
||||
</form>\
|
||||
</div>";
|
||||
step.ui.querySelector("div.details").appendChild(div);
|
||||
}
|
||||
|
||||
function toggleSaveButton() {
|
||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled", false);
|
||||
focusInput();
|
||||
}
|
||||
|
||||
$(step.ui.querySelectorAll(".target")).on('change', toggleSaveButton);
|
||||
|
||||
$(step.ui.querySelector("div.details")).append(
|
||||
"<p><button class='btn btn-default btn-save' disabled = 'true' >Apply</button><span> Press apply to see changes</span></p>"
|
||||
'<div class="cal"><p><button type="submit" class="btn btn-default btn-save" disabled = "true" >Apply</button><span> Press apply to see changes</span></p></div>'
|
||||
);
|
||||
|
||||
function focusInput() {
|
||||
$(step.ui.querySelector("div.details .target")).focus();
|
||||
}
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
$(step.ui.querySelector("div.details"))
|
||||
.find("input,select")
|
||||
.each(function(i, input) {
|
||||
step.options[$(input).attr("name")] = input.value;
|
||||
});
|
||||
_sequencer.run({ index: step.index - 1 });
|
||||
|
||||
// modify the url hash
|
||||
setUrlHashParameter("steps", _sequencer.toString());
|
||||
// disable the save button
|
||||
$(step.ui.querySelector("div.details .btn-save")).prop("disabled", true);
|
||||
}
|
||||
|
||||
// on clicking Save in the details pane of the step
|
||||
$(step.ui.querySelector("div.details .btn-save")).click(saveOptions);
|
||||
$(step.ui.querySelector("div.details .input-form")).on('submit', saveOptions);
|
||||
|
||||
}
|
||||
|
||||
if (step.name != "load-image") {
|
||||
@@ -168,13 +135,14 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
.appendChild(
|
||||
parser.parseFromString(tools, "text/html").querySelector("div")
|
||||
);
|
||||
$(step.ui.querySelectorAll(".remove")).on('click', function() {notify('Step Removed','remove-notification')});
|
||||
$(step.ui.querySelectorAll(".insert-step")).on('click', function() { util.insertStep(step.ID) });
|
||||
|
||||
// Insert the step's UI in the right place
|
||||
if (stepOptions.index == _sequencer.images.image1.steps.length) {
|
||||
stepsEl.appendChild(step.ui);
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
if($("#steps .container:nth-last-child(2)"))
|
||||
if($("#steps .container:nth-last-child(2)"))
|
||||
$("#steps .container:nth-last-child(2) .insert-step").prop('disabled',false);
|
||||
} else {
|
||||
stepsEl.insertBefore(step.ui, $(stepsEl).children()[stepOptions.index]);
|
||||
@@ -183,22 +151,86 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
else {
|
||||
$("#load-image").append(step.ui);
|
||||
}
|
||||
$(step.ui.querySelector(".toggle")).on("click", () => {
|
||||
$(step.ui.querySelector('.toggleIcon')).toggleClass('fa-caret-up').toggleClass('fa-caret-down');
|
||||
$(step.ui.querySelectorAll(".cal")).toggleClass("collapse");
|
||||
});
|
||||
|
||||
|
||||
function saveOptions(e) {
|
||||
e.preventDefault();
|
||||
if (optionsChanged){
|
||||
$(step.ui.querySelector("div.details"))
|
||||
.find("input,select")
|
||||
.each(function(i, input) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false);
|
||||
step.options[$(input).attr("name")] = $(input).val();
|
||||
});
|
||||
_sequencer.run({ index: step.index - 1 });
|
||||
|
||||
// modify the url hash
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
// disable the save button
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', true);
|
||||
optionsChanged = false;
|
||||
changedInputs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function handleInputValueChange(currentValue, initValue, hasChangedBefore) {
|
||||
var inputChanged = !(isNaN(initValue) || isNaN(currentValue) ? currentValue === initValue : currentValue - initValue === 0);
|
||||
changedInputs += hasChangedBefore ? inputChanged ? 0 : -1 : inputChanged ? 1 : 0;
|
||||
optionsChanged = changedInputs > 0;
|
||||
|
||||
$(step.ui.querySelector('.btn-save')).prop('disabled', !optionsChanged);
|
||||
return inputChanged;
|
||||
}
|
||||
|
||||
var
|
||||
changedInputs = 0,
|
||||
optionsChanged = false;
|
||||
$(step.ui.querySelector('.input-form')).on('submit', saveOptions);
|
||||
$(step.ui.querySelectorAll('.target')).each(function(i, input) {
|
||||
$(input)
|
||||
.data('initValue', $(input).val())
|
||||
.data('hasChangedBefore', false)
|
||||
.on('input', function() {
|
||||
$(this)
|
||||
.focus()
|
||||
.data('hasChangedBefore',
|
||||
handleInputValueChange(
|
||||
$(this).val(),
|
||||
$(this).data('initValue'),
|
||||
$(this).data('hasChangedBefore')
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
$('input[type="range"]').on('input', function() {
|
||||
$(this).next().html($(this).val());
|
||||
})
|
||||
}
|
||||
|
||||
var inputs = document.querySelectorAll('input[type="range"]')
|
||||
for (i in inputs)
|
||||
inputs[i].oninput = function(e) {
|
||||
e.target.nextSibling.innerHTML = e.target.value;
|
||||
}
|
||||
|
||||
function onDraw(step) {
|
||||
$(step.ui.querySelector(".load")).show();
|
||||
$(step.ui.querySelector("img")).hide();
|
||||
if( $(step.ui.querySelector(".toggleIcon")).hasClass("fa-caret-down") )
|
||||
{
|
||||
$(step.ui.querySelector(".load-spin")).show();
|
||||
}
|
||||
}
|
||||
|
||||
function onComplete(step) {
|
||||
$(step.ui.querySelector(".load")).hide();
|
||||
$(step.ui.querySelector("img")).show();
|
||||
$(step.ui.querySelector(".load-spin")).hide();
|
||||
|
||||
step.imgElement.src = step.output;
|
||||
var imgthumbnail = step.ui.querySelector(".img-thumbnail");
|
||||
@@ -224,17 +256,19 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
for (var i in inputs) {
|
||||
if (step.options[i] !== undefined) {
|
||||
if (inputs[i].type.toLowerCase() === "input")
|
||||
step.ui.querySelector('div[name="' + i + '"] input').value =
|
||||
step.options[i];
|
||||
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||
.val(step.options[i])
|
||||
.data('initValue', step.options[i]);
|
||||
if (inputs[i].type.toLowerCase() === "select")
|
||||
step.ui.querySelector('div[name="' + i + '"] select').value =
|
||||
step.options[i];
|
||||
$(step.ui.querySelector('div[name="' + i + '"] select'))
|
||||
.val(step.options[i])
|
||||
.data('initValue', step.options[i]);
|
||||
}
|
||||
}
|
||||
for (var i in outputs) {
|
||||
if (step[i] !== undefined)
|
||||
step.ui.querySelector('div[name="' + i + '"] input').value =
|
||||
step[i];
|
||||
$(step.ui.querySelector('div[name="' + i + '"] input'))
|
||||
.val(step[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,17 +276,41 @@ function DefaultHtmlStepUi(_sequencer, options) {
|
||||
function onRemove(step) {
|
||||
step.ui.remove();
|
||||
$("#steps .container:nth-last-child(1) .insert-step").prop('disabled',true);
|
||||
$('div[class^=imgareaselect-]').remove();
|
||||
}
|
||||
|
||||
function getPreview() {
|
||||
return step.imgElement;
|
||||
}
|
||||
|
||||
function notify(msg,id){
|
||||
if ($('#'+id).length == 0) {
|
||||
var notification = document.createElement('span');
|
||||
notification.innerHTML = ' <i class="fa fa-info-circle" aria-hidden="true"></i> ' + msg ;
|
||||
notification.id = id;
|
||||
notification.classList.add("notification");
|
||||
|
||||
$('body').append(notification);
|
||||
}
|
||||
|
||||
$('#'+id).fadeIn(500).delay(200).fadeOut(500);
|
||||
}
|
||||
|
||||
return {
|
||||
getPreview: getPreview,
|
||||
onSetup: onSetup,
|
||||
onComplete: onComplete,
|
||||
onRemove: onRemove,
|
||||
onDraw: onDraw
|
||||
onDraw: onDraw,
|
||||
notify: notify
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(typeof window === "undefined"){
|
||||
module.exports={
|
||||
DefaultHtmlStepUi: DefaultHtmlStepUi
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultHtmlStepUi;
|
||||
|
||||
|
||||
55
examples/lib/insertPreview.js
Normal file
55
examples/lib/insertPreview.js
Normal file
@@ -0,0 +1,55 @@
|
||||
function generatePreview(previewStepName, customValues, path, selector) {
|
||||
|
||||
var previewSequencer = ImageSequencer();
|
||||
function insertPreview(src) {
|
||||
var img = document.createElement('img');
|
||||
img.classList.add('img-thumbnail')
|
||||
img.classList.add('no-border');
|
||||
img.src = src;
|
||||
$(img).css("max-width", "200%");
|
||||
$(img).css("transform", "translateX(-20%)");
|
||||
var stepDiv = $('#'+selector+' .row').find('div').each(function() {
|
||||
if ($(this).find('div').attr('data-value') === previewStepName) {
|
||||
$(this).find('div').append(img);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadPreview() {
|
||||
previewSequencer = previewSequencer.addSteps('resize', { resize: "40%" });
|
||||
if (previewStepName === "crop") {
|
||||
previewSequencer.addSteps(previewStepName, customValues).run(insertPreview);
|
||||
}
|
||||
else {
|
||||
previewSequencer.addSteps(previewStepName, { [previewStepName]: customValues }).run(insertPreview);
|
||||
}
|
||||
}
|
||||
previewSequencer.loadImage(path, loadPreview);
|
||||
}
|
||||
|
||||
function updatePreviews(src, selector) {
|
||||
$('#'+selector+' img').remove();
|
||||
|
||||
var previewSequencerSteps = {
|
||||
"brightness": "20",
|
||||
"saturation": "5",
|
||||
"rotate": 90,
|
||||
"contrast": 90,
|
||||
"crop": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": "(50%)",
|
||||
"h": "(50%)",
|
||||
"noUI": true
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(previewSequencerSteps).forEach(function (step, index) {
|
||||
generatePreview(step, Object.values(previewSequencerSteps)[index], src, selector);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generatePreview : generatePreview,
|
||||
updatePreviews : updatePreviews
|
||||
}
|
||||
@@ -1,40 +1,41 @@
|
||||
var urlHash = require('./urlHash.js');
|
||||
function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
function stepUI() {
|
||||
return '<div class="row insertDiv">\
|
||||
<div class="col-md-6" style="margin-top:5%">\
|
||||
<div class="col-md-6 col-md-offset-2" style="margin-top:5%">\
|
||||
<section id="insertStep" class="panel panel-primary">\
|
||||
<div class="form-inline">\
|
||||
<div class="panel-body">\
|
||||
<p class="info">Select a new module to add to your sequence.</p>\
|
||||
<div class="row center-align radio-group">\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="brightness">\
|
||||
<i class="fa fa-sun-o fa-4x"></i>\
|
||||
</button>\
|
||||
<div class="radio" data-value="brightness">\
|
||||
<i class="fa fa-sun-o fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Brightness</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="contrast">\
|
||||
<i class="fa fa-adjust fa-4x"></i>\
|
||||
</button>\
|
||||
<div class="radio" data-value="contrast">\
|
||||
<i class="fa fa-adjust fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Contrast</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="saturation">\
|
||||
<i class="fa fa-tint fa-4x"></i>\
|
||||
</button>\
|
||||
<div class="radio" data-value="saturation">\
|
||||
<i class="fa fa-tint fa-4x i-over i-small"></i>\
|
||||
</div>\
|
||||
<p>Saturation</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="rotate">\
|
||||
<i class="fa fa-rotate-right fa-4x"></i>\
|
||||
</button>\
|
||||
<div class="radio" data-value="rotate">\
|
||||
<i class="fa fa-rotate-right fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Rotate</p>\
|
||||
</div>\
|
||||
<div>\
|
||||
<button type="button" class="btn btn-default btn-circle btn-xl radio" data-value="crop">\
|
||||
<i class="fa fa-crop fa-4x"></i>\
|
||||
</button>\
|
||||
<div class="radio" data-value="crop">\
|
||||
<i class="fa fa-crop fa-4x i-over"></i>\
|
||||
</div>\
|
||||
<p>Crop</p>\
|
||||
</div>\
|
||||
</div>\
|
||||
@@ -50,12 +51,14 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
</section>\
|
||||
</div>';
|
||||
}
|
||||
|
||||
|
||||
function selectNewStepUi() {
|
||||
var m = $("#insertStep select").val();
|
||||
$("#insertStep .info").html(_sequencer.modulesInfo(m).description);
|
||||
$("#insertStep #add-step-btn").prop("disabled", false);
|
||||
}
|
||||
insertStep = function(id) {
|
||||
insertStep = function (id) {
|
||||
var modulesInfo = _sequencer.modulesInfo();
|
||||
var parser = new DOMParser();
|
||||
var addStepUI = stepUI();
|
||||
@@ -65,6 +68,7 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
.insertAdjacentElement('afterend',
|
||||
addStepUI
|
||||
);
|
||||
updatePreviews(step.output,'insertStep');
|
||||
var insertStepSelect = $("#insertStep select");
|
||||
insertStepSelect.html("");
|
||||
// Add modules to the insertStep dropdown
|
||||
@@ -78,7 +82,7 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
$('#insertStep #add-step-btn').prop('disabled', true);
|
||||
|
||||
insertStepSelect.append('<option value="none" disabled selected>More modules...</option>');
|
||||
$('#insertStep .radio-group .radio').on("click", function() {
|
||||
$('#insertStep .radio-group .radio').on("click", function () {
|
||||
$(this).parent().find('.radio').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
newStep = $(this).attr('data-value');
|
||||
@@ -88,7 +92,7 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
$(this).removeClass('selected');
|
||||
});
|
||||
$(step.ui.querySelector("#insertStep select")).on('change', selectNewStepUi);
|
||||
$(step.ui.querySelector("#insertStep #add-step-btn")).on('click', function() { insert(id) });
|
||||
$(step.ui.querySelector("#insertStep #add-step-btn")).on('click', function () { insert(id) });
|
||||
}
|
||||
|
||||
function insert(id) {
|
||||
@@ -109,10 +113,13 @@ function IntermediateHtmlStepUi(_sequencer, step, options) {
|
||||
.insertSteps(id + 1, newStepName).run({ index: id });
|
||||
|
||||
// add to URL hash too
|
||||
setUrlHashParameter("steps", _sequencer.toString());
|
||||
urlHash.setUrlHashParameter("steps", _sequencer.toString());
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
insertStep
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = IntermediateHtmlStepUi;
|
||||
|
||||
|
||||
35
examples/lib/sw.js
Normal file
35
examples/lib/sw.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const staticCacheName = 'image-sequencer-static-v3';
|
||||
|
||||
self.addEventListener('install', event => {
|
||||
console.log('Attempting to install service worker');
|
||||
});
|
||||
|
||||
self.addEventListener('activate', function(e) {
|
||||
console.log('[ServiceWorker] Activate');
|
||||
e.waitUntil(
|
||||
caches.keys().then(function(cacheNames) {
|
||||
return Promise.all(
|
||||
cacheNames.filter(function(cacheName){
|
||||
return cacheName.startsWith('image-sequencer-') &&
|
||||
cacheName != staticCacheName;
|
||||
}).map(function(cacheName){
|
||||
return caches.delete(cacheName);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', function(event) {
|
||||
event.respondWith(
|
||||
caches.open(staticCacheName).then(function(cache) {
|
||||
return cache.match(event.request).then(function (response) {
|
||||
return response || fetch(event.request).then(function(response) {
|
||||
if(event.request.method == "GET")
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -40,3 +40,10 @@ function setUrlHashParameter(param, value) {
|
||||
setUrlHashParameters(params);
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getUrlHashParameter: getUrlHashParameter,
|
||||
setUrlHashParameter: setUrlHashParameter,
|
||||
getUrlHashParameters: getUrlHashParameters,
|
||||
setUrlHashParameters: setUrlHashParameters
|
||||
}
|
||||
|
||||
158
index.js
158
index.js
@@ -1,11 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require("./src/ImageSequencer");
|
||||
require('./src/ImageSequencer');
|
||||
sequencer = ImageSequencer({ ui: false });
|
||||
var Spinner = require("ora");
|
||||
var fs = require('fs')
|
||||
var program = require('commander');
|
||||
var utils = require('./src/CliUtils')
|
||||
|
||||
var program = require("commander");
|
||||
var readlineSync = require("readline-sync");
|
||||
var saveSequence = require('./src/cli/saveSequence.js')
|
||||
var installModule = require('./src/cli/installModule.js')
|
||||
var sequencerSteps = require('./src/cli/sequencerSteps.js')
|
||||
|
||||
function exit(message) {
|
||||
console.error(message);
|
||||
@@ -23,24 +26,11 @@ program
|
||||
.option('--install-module [string]', "Module name space seaprated npm package name")
|
||||
.parse(process.argv);
|
||||
|
||||
if (program.saveSequence) {
|
||||
var params = program.saveSequence.split(' ');
|
||||
sequencer.saveSequence(params[0], params[1]);
|
||||
console.log("\x1b[32m", "Your sequence was saved successfully!!");
|
||||
} else if (program.installModule) {
|
||||
console.log(
|
||||
"\x1b[33m%s\x1b[0m",
|
||||
"Please wait while your Module is being Installed...\nThis may take a while!"
|
||||
);
|
||||
|
||||
var params = program.installModule.split(' ');
|
||||
var spinner = Spinner("Now Installing...").start();
|
||||
require('child_process').execSync(`npm i ${params[1]}`)
|
||||
sequencer.saveNewModule(params[0], params[1]);
|
||||
sequencer.loadNewModule(params[0], require(params[1]));
|
||||
spinner.stop();
|
||||
console.log("\x1b[32m%s\x1b[0m", "Your module was installed successfully!!");
|
||||
} else {
|
||||
if (program.saveSequence) saveSequence(program, sequencer)
|
||||
|
||||
else if (program.installModule) installModule(program, sequencer)
|
||||
|
||||
else {
|
||||
// Parse step into an array to allow for multiple steps.
|
||||
if (!program.step) exit("No steps passed");
|
||||
program.step = program.step.split(" ");
|
||||
@@ -49,12 +39,12 @@ if (program.saveSequence) {
|
||||
if (!program.image) exit("Can't read file.");
|
||||
|
||||
// User must input an image.
|
||||
require("fs").access(program.image, function(err) {
|
||||
fs.access(program.image, function(err) {
|
||||
if (err) exit("Can't read file.");
|
||||
});
|
||||
|
||||
// User must input a step. If steps exist, check that every step is a valid step.
|
||||
if (!program.step || !validateSteps(program.step))
|
||||
if (!program.step || !(utils.validateSteps(program.step, sequencer)))
|
||||
exit("Please ensure all steps are valid.");
|
||||
|
||||
// If there's no user defined output directory, select a default directory.
|
||||
@@ -69,6 +59,9 @@ if (program.saveSequence) {
|
||||
for (var output in step.info.outputs) {
|
||||
console.log("[" + program.step + "]: " + output + " = " + step[output]);
|
||||
}
|
||||
},
|
||||
notify: function(msg) {
|
||||
console.log('\x1b[36m%s\x1b[0m','🌟 '+msg);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -88,124 +81,9 @@ if (program.saveSequence) {
|
||||
else {
|
||||
outputFilename = null;
|
||||
}
|
||||
require("./src/CliUtils").makedir(program.output, () => {
|
||||
console.log('Files will be exported to "' + program.output + '"');
|
||||
|
||||
if (program.basic)
|
||||
console.log("Basic mode is enabled, outputting only final image");
|
||||
sequencerSteps(program, sequencer, outputFilename)
|
||||
|
||||
// Iterate through the steps and retrieve their inputs.
|
||||
program.step.forEach(function(step) {
|
||||
var options = Object.assign({}, sequencer.modulesInfo(step).inputs);
|
||||
|
||||
// If inputs exists, print to console.
|
||||
if (Object.keys(options).length) {
|
||||
console.log("[" + step + "]: Inputs");
|
||||
}
|
||||
|
||||
// If inputs exists, print them out with descriptions.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
// The array below creates a variable number of spaces. This is done with (length + 1).
|
||||
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
||||
console.log(
|
||||
new Array(step.length + 5).join(" ") +
|
||||
input +
|
||||
": " +
|
||||
options[input].desc
|
||||
);
|
||||
});
|
||||
|
||||
if (program.config) {
|
||||
try {
|
||||
var config = JSON.parse(program.config);
|
||||
console.log(`The parsed options object: `, config);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options(Config) is not a not valid JSON Fallback activate`
|
||||
);
|
||||
program.config = false;
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
if (program.config && validateConfig(config, options)) {
|
||||
console.log("Now using Options object");
|
||||
Object.keys(options).forEach(function(input) {
|
||||
options[input] = config[input];
|
||||
});
|
||||
} else {
|
||||
// If inputs exist, iterate through them and prompt for values.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
var value = readlineSync.question(
|
||||
"[" +
|
||||
step +
|
||||
"]: Enter a value for " +
|
||||
input +
|
||||
" (" +
|
||||
options[input].type +
|
||||
", default: " +
|
||||
options[input].default +
|
||||
"): "
|
||||
);
|
||||
options[input] = value;
|
||||
});
|
||||
}
|
||||
// Add the step and its inputs to the sequencer.
|
||||
sequencer.addSteps(step, options);
|
||||
});
|
||||
|
||||
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
||||
if (!process.env.TEST)
|
||||
spinnerObj = Spinner("Your Image is being processed..").start();
|
||||
|
||||
// Run the sequencer.
|
||||
sequencer.run({ progressObj: spinnerObj }, function() {
|
||||
// Export all images or final image as binary files.
|
||||
sequencer.exportBin(program.output, program.basic, outputFilename);
|
||||
|
||||
//check if spinner was not overriden stop it
|
||||
if (!spinnerObj.overrideFlag) {
|
||||
spinnerObj.succeed();
|
||||
console.log(`\nDone!!`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
||||
function validateSteps(steps) {
|
||||
// Assume all are valid in the beginning.
|
||||
var valid = true;
|
||||
steps.forEach(function(step) {
|
||||
// If any step in the array is not valid (not a property of modulesInfo), set valid to false.
|
||||
if (!sequencer.modulesInfo().hasOwnProperty(step)) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return valid. (If all of the steps are valid properties, valid will have remained true).
|
||||
return valid;
|
||||
}
|
||||
|
||||
//Takes config and options object and checks if all the keys exist in config
|
||||
function validateConfig(config_, options_) {
|
||||
options_ = Object.keys(options_);
|
||||
if (
|
||||
(function() {
|
||||
for (var input in options_) {
|
||||
if (!config_[options_[input]]) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options Object does not have the required details "${
|
||||
options_[input]
|
||||
}" not specified. Fallback case activated`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})() == false
|
||||
)
|
||||
return false;
|
||||
else return true;
|
||||
}
|
||||
}
|
||||
|
||||
922
package-lock.json
generated
922
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "image-sequencer",
|
||||
"version": "2.2.3",
|
||||
"version": "2.3.1",
|
||||
"description": "A modular JavaScript image manipulation library modeled on a storyboard.",
|
||||
"main": "src/ImageSequencer.js",
|
||||
"scripts": {
|
||||
"debug": "TEST=true node ./index.js -i ./examples/images/monarch.png -s invert",
|
||||
"test": "TEST=true tape test/**/*.js test/*.js | tap-spec; browserify test/modules/image-sequencer.js test/modules/chain.js test/modules/meta-modules.js test/modules/replace.js test/modules/import-export.js test/modules/run.js test/modules/dynamic-imports.js | tape-run --render=\"tap-spec\"",
|
||||
"test": "TEST=true tape test/core/*.js test/core/ui/user-interface.js | tap-spec; browserify test/core/modules/image-sequencer.js test/core/modules/chain.js test/core/modules/meta-modules.js test/core/modules/replace.js test/core/modules/import-export.js test/core/modules/run.js test/core/modules/dynamic-imports.js test/core/util/parse-input.js | tape-run --render=\"tap-spec\"",
|
||||
"test-ui": "jasmine",
|
||||
"setup": "npm i && npm i -g grunt grunt-cli",
|
||||
"start": "grunt serve"
|
||||
},
|
||||
@@ -31,11 +32,13 @@
|
||||
"fisheyegl": "^0.1.2",
|
||||
"font-awesome": "~4.7.0",
|
||||
"get-pixels": "~3.3.0",
|
||||
"gifshot": "^0.4.5",
|
||||
"image-sequencer-invert": "^1.0.0",
|
||||
"imagejs": "0.0.9",
|
||||
"imgareaselect": "git://github.com/jywarren/imgareaselect.git#v1.0.0-rc.2",
|
||||
"jquery": "^3.3.1",
|
||||
"jsqr": "^0.2.2",
|
||||
"jsdom": "^13.1.0",
|
||||
"jsqr": "^1.1.1",
|
||||
"lodash": "^4.17.5",
|
||||
"ndarray-gaussian-filter": "^1.0.0",
|
||||
"ora": "^3.0.0",
|
||||
@@ -54,10 +57,13 @@
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"image-filter-core": "~2.0.2",
|
||||
"image-filter-threshold": "~2.0.1",
|
||||
"looks-same": "^4.1.0",
|
||||
"jasmine-core": "^3.3.0",
|
||||
"jasmine-jquery": "^2.1.1",
|
||||
"jasmine-spec-reporter": "^4.2.1",
|
||||
"looks-same": "^5.0.1",
|
||||
"matchdep": "^2.0.0",
|
||||
"tap-spec": "^5.0.0",
|
||||
"tape": ">=4.7.0",
|
||||
"tape": "^4.9.2",
|
||||
"tape-run": "^5.0.0",
|
||||
"uglify-es": "^3.3.7"
|
||||
},
|
||||
|
||||
42
spec/defaultHtmlSequencerUi.spec.js
Normal file
42
spec/defaultHtmlSequencerUi.spec.js
Normal file
@@ -0,0 +1,42 @@
|
||||
describe('Default sequencer HTML', function() {
|
||||
|
||||
var DefaultHtmlSequencerUi = require('../examples/lib/defaultHtmlSequencerUi')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var defaultHtmlSequencerUi;
|
||||
|
||||
beforeEach(()=>{
|
||||
defaultHtmlSequencerUi = new DefaultHtmlSequencerUi(sequencer)
|
||||
|
||||
spyOn(defaultHtmlSequencerUi,'onLoad')
|
||||
spyOn(defaultHtmlSequencerUi,'selectNewStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'removeStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'addStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'importStepsFromUrlHash')
|
||||
|
||||
defaultHtmlSequencerUi.onLoad()
|
||||
defaultHtmlSequencerUi.selectNewStepUi()
|
||||
defaultHtmlSequencerUi.addStepUi()
|
||||
defaultHtmlSequencerUi.removeStepUi()
|
||||
defaultHtmlSequencerUi.importStepsFromUrlHash()
|
||||
})
|
||||
|
||||
it('load default ui', function() {
|
||||
expect(defaultHtmlSequencerUi.onLoad).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('select step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.selectNewStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('add step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.addStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('remove step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.removeStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('import options from url', function() {
|
||||
expect(defaultHtmlSequencerUi.importStepsFromUrlHash).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
61
spec/defaultHtmlStepUi.spec.js
Normal file
61
spec/defaultHtmlStepUi.spec.js
Normal file
@@ -0,0 +1,61 @@
|
||||
var { JSDOM } = require('jsdom');
|
||||
var DOM = new JSDOM(`<body></body>`);
|
||||
|
||||
global.document = DOM.window.document;
|
||||
|
||||
describe('Sequencer step HTML', function() {
|
||||
|
||||
var DefaultHtmlStepUi = require('../examples/lib/defaultHtmlStepUi')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var defaultHtmlStepUi;
|
||||
var step = 'brightness'
|
||||
var options = {
|
||||
name: "Brightness",
|
||||
description: "Change the brightness of the image by given percent value"
|
||||
}
|
||||
// options = JSON.parse(options)
|
||||
|
||||
beforeEach(()=>{
|
||||
defaultHtmlStepUi = new DefaultHtmlStepUi(sequencer)
|
||||
|
||||
spyOn(defaultHtmlStepUi,'getPreview')
|
||||
spyOn(defaultHtmlStepUi,'onSetup')
|
||||
spyOn(defaultHtmlStepUi,'onComplete')
|
||||
spyOn(defaultHtmlStepUi,'onDraw')
|
||||
spyOn(defaultHtmlStepUi,'onRemove')
|
||||
spyOn(defaultHtmlStepUi,'notify')
|
||||
|
||||
defaultHtmlStepUi.getPreview()
|
||||
defaultHtmlStepUi.onSetup(step,options)
|
||||
defaultHtmlStepUi.onComplete(step)
|
||||
defaultHtmlStepUi.onDraw(step)
|
||||
defaultHtmlStepUi.onRemove(step)
|
||||
defaultHtmlStepUi.notify('Step removed','remove-notification')
|
||||
})
|
||||
|
||||
|
||||
it('result preview ui', function() {
|
||||
expect(defaultHtmlStepUi.getPreview).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('load initial setup ui', function() {
|
||||
expect(defaultHtmlStepUi.onSetup).toHaveBeenCalledWith(step,options)
|
||||
})
|
||||
|
||||
it('load completion ui', function() {
|
||||
expect(defaultHtmlStepUi.onComplete).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('draw step ui', function() {
|
||||
expect(defaultHtmlStepUi.onDraw).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('remove step ui', function() {
|
||||
expect(defaultHtmlStepUi.onRemove).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('notification ui', function() {
|
||||
expect(defaultHtmlStepUi.notify).toHaveBeenCalledWith('Step removed','remove-notification')
|
||||
})
|
||||
|
||||
})
|
||||
8
spec/helpers/reporter.js
Normal file
8
spec/helpers/reporter.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||
|
||||
jasmine.getEnv().clearReporters(); // remove default reporter logs
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter
|
||||
spec: {
|
||||
displayPending: true
|
||||
}
|
||||
}));
|
||||
26
spec/insertPreview.spec.js
Normal file
26
spec/insertPreview.spec.js
Normal file
@@ -0,0 +1,26 @@
|
||||
describe('Preview UI HTML', function() {
|
||||
|
||||
var InsertPreview = require('../examples/lib/insertPreview')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var insertPreview;
|
||||
var options = { brightness: 50 }
|
||||
|
||||
beforeEach(()=>{
|
||||
insertPreview = InsertPreview
|
||||
|
||||
spyOn(insertPreview,'generatePreview')
|
||||
spyOn(insertPreview,'updatePreviews')
|
||||
|
||||
insertPreview.generatePreview('brightness',options,'src','selector')
|
||||
insertPreview.updatePreviews('src','selector')
|
||||
})
|
||||
|
||||
it('generate preview ui', function() {
|
||||
expect(insertPreview.generatePreview).toHaveBeenCalledWith('brightness',options,'src','selector')
|
||||
})
|
||||
|
||||
it('update preview ui', function() {
|
||||
expect(insertPreview.updatePreviews).toHaveBeenCalledWith('src','selector')
|
||||
})
|
||||
|
||||
})
|
||||
19
spec/intermediateHtmlStepUi.spec.js
Normal file
19
spec/intermediateHtmlStepUi.spec.js
Normal file
@@ -0,0 +1,19 @@
|
||||
describe('Intermediate step HTML', function() {
|
||||
|
||||
var IntermediateHtmlStepUi = require('../examples/lib/intermediateHtmlStepUi')
|
||||
var sequencer = require('../src/ImageSequencer')()
|
||||
var intermediateHtmlStepUi;
|
||||
|
||||
beforeEach(()=>{
|
||||
intermediateHtmlStepUi = new IntermediateHtmlStepUi(sequencer)
|
||||
|
||||
spyOn(intermediateHtmlStepUi,'insertStep')
|
||||
|
||||
intermediateHtmlStepUi.insertStep()
|
||||
})
|
||||
|
||||
it('insert step ui', function() {
|
||||
expect(intermediateHtmlStepUi.insertStep).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
})
|
||||
11
spec/support/jasmine.json
Normal file
11
spec/support/jasmine.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.js"
|
||||
],
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
40
spec/urlHash.spec.js
Normal file
40
spec/urlHash.spec.js
Normal file
@@ -0,0 +1,40 @@
|
||||
describe('URL manipulation methods', function() {
|
||||
|
||||
var UrlHash = require('../examples/lib/urlHash')
|
||||
var urlHash;
|
||||
var params = {
|
||||
module: 'brightness',
|
||||
brightness: 50
|
||||
}
|
||||
|
||||
beforeEach(()=>{
|
||||
urlHash = UrlHash
|
||||
|
||||
spyOn(urlHash,'getUrlHashParameters')
|
||||
spyOn(urlHash,'getUrlHashParameter')
|
||||
spyOn(urlHash,'setUrlHashParameters')
|
||||
spyOn(urlHash,'setUrlHashParameter')
|
||||
|
||||
urlHash.getUrlHashParameters()
|
||||
urlHash.getUrlHashParameter('module')
|
||||
urlHash.setUrlHashParameters(params)
|
||||
urlHash.setUrlHashParameter('module','brightness')
|
||||
})
|
||||
|
||||
it('gets url hash params from window hash', function() {
|
||||
expect(urlHash.getUrlHashParameters).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('gets url hash param from params object', function() {
|
||||
expect(urlHash.getUrlHashParameter).toHaveBeenCalledWith('module')
|
||||
})
|
||||
|
||||
it('accepts param object and sets url hash params', function() {
|
||||
expect(urlHash.setUrlHashParameters).toHaveBeenCalledWith(params)
|
||||
})
|
||||
|
||||
it('accepts param key-value pair and sets url hash params', function() {
|
||||
expect(urlHash.setUrlHashParameter).toHaveBeenCalledWith('module','brightness')
|
||||
})
|
||||
|
||||
})
|
||||
@@ -1,6 +1,4 @@
|
||||
const fs = require('fs')
|
||||
|
||||
|
||||
var fs = require('fs')
|
||||
|
||||
/*
|
||||
* This function checks if the directory exists, if not it creates one on the given path
|
||||
@@ -16,6 +14,45 @@ function makedir(path,callback){
|
||||
});
|
||||
};
|
||||
|
||||
// Takes an array of steps and checks if they are valid steps for the sequencer.
|
||||
function validateSteps(steps, sequencer) {
|
||||
// Assume all are valid in the beginning.
|
||||
var valid = true;
|
||||
steps.forEach(function(step) {
|
||||
// If any step in the array is not valid (not a property of modulesInfo), set valid to false.
|
||||
if (!sequencer.modulesInfo().hasOwnProperty(step)) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Return valid. (If all of the steps are valid properties, valid will have remained true).
|
||||
return valid;
|
||||
}
|
||||
|
||||
//Takes config and options object and checks if all the keys exist in config
|
||||
function validateConfig(config_, options_) {
|
||||
options_ = Object.keys(options_);
|
||||
if (
|
||||
(function() {
|
||||
for (var input in options_) {
|
||||
if (!config_[options_[input]]) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options Object does not have the required details "${
|
||||
options_[input]
|
||||
}" not specified. Fallback case activated`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})() == false
|
||||
)
|
||||
return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
module.exports = exports = {
|
||||
makedir: makedir
|
||||
makedir: makedir,
|
||||
validateSteps: validateSteps,
|
||||
validateConfig: validateConfig
|
||||
}
|
||||
@@ -132,7 +132,7 @@ ImageSequencer = function ImageSequencer(options) {
|
||||
// Config is an object which contains the runtime configuration like progress bar
|
||||
// information and index from which the sequencer should run
|
||||
function run(config, t_image, t_from) {
|
||||
let progressObj, index = 0;
|
||||
var progressObj, index = 0;
|
||||
config = config || { mode: 'no-arg' };
|
||||
if (config.index) index = config.index;
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ module.exports = {
|
||||
'convolution': require('./modules/Convolution'),
|
||||
'crop': require('./modules/Crop'),
|
||||
'decode-qr': require('./modules/DecodeQr'),
|
||||
'dither': require('./modules/Dither'),
|
||||
'draw-rectangle': require('./modules/DrawRectangle'),
|
||||
'dynamic': require('./modules/Dynamic'),
|
||||
'edge-detect': require('./modules/EdgeDetect'),
|
||||
'fisheye-gl': require('./modules/FisheyeGl'),
|
||||
@@ -23,8 +25,10 @@ module.exports = {
|
||||
'invert': require('image-sequencer-invert'),
|
||||
'ndvi': require('./modules/Ndvi'),
|
||||
'ndvi-colormap': require('./modules/NdviColormap'),
|
||||
'paint-bucket': require('./modules/PaintBucket'),
|
||||
'overlay': require('./modules/Overlay'),
|
||||
'resize': require('./modules/Resize'),
|
||||
'rotate': require('./modules/Rotate'),
|
||||
'saturation': require('./modules/Saturation')
|
||||
}
|
||||
'saturation': require('./modules/Saturation'),
|
||||
'white-balance': require('./modules/WhiteBalance')
|
||||
}
|
||||
17
src/cli/installModule.js
Normal file
17
src/cli/installModule.js
Normal file
@@ -0,0 +1,17 @@
|
||||
var childProcess = require('child_process')
|
||||
var Spinner = require('ora');
|
||||
|
||||
module.exports = function (program, sequencer) {
|
||||
console.log(
|
||||
"\x1b[33m%s\x1b[0m",
|
||||
"Please wait while your Module is being Installed...\nThis may take a while!"
|
||||
);
|
||||
|
||||
var params = program.installModule.split(' ');
|
||||
var spinner = Spinner("Now Installing...").start();
|
||||
childProcess.execSync(`npm i ${params[1]}`)
|
||||
sequencer.saveNewModule(params[0], params[1]);
|
||||
sequencer.loadNewModule(params[0], require(params[1]));
|
||||
spinner.stop();
|
||||
console.log("\x1b[32m%s\x1b[0m", "Your module was installed successfully!!");
|
||||
}
|
||||
7
src/cli/saveSequence.js
Normal file
7
src/cli/saveSequence.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = function (program, sequencer) {
|
||||
|
||||
var params = program.saveSequence.split(' ');
|
||||
sequencer.saveSequence(params[0], params[1]);
|
||||
console.log("\x1b[32m", "Your sequence was saved successfully!!");
|
||||
|
||||
}
|
||||
88
src/cli/sequencerSteps.js
Normal file
88
src/cli/sequencerSteps.js
Normal file
@@ -0,0 +1,88 @@
|
||||
var Spinner = require('ora');
|
||||
var readlineSync = require('readline-sync');
|
||||
var utils = require('../CliUtils')
|
||||
|
||||
module.exports = function (program, sequencer, outputFilename) {
|
||||
utils.makedir(program.output, () => {
|
||||
console.log('Files will be exported to "' + program.output + '"');
|
||||
|
||||
if (program.basic)
|
||||
console.log("Basic mode is enabled, outputting only final image");
|
||||
|
||||
// Iterate through the steps and retrieve their inputs.
|
||||
program.step.forEach(function(step) {
|
||||
var options = Object.assign({}, sequencer.modulesInfo(step).inputs);
|
||||
|
||||
// If inputs exists, print to console.
|
||||
if (Object.keys(options).length) {
|
||||
console.log("[" + step + "]: Inputs");
|
||||
}
|
||||
|
||||
// If inputs exists, print them out with descriptions.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
// The array below creates a variable number of spaces. This is done with (length + 1).
|
||||
// The extra 4 that makes it (length + 5) is to account for the []: characters
|
||||
console.log(
|
||||
new Array(step.length + 5).join(" ") +
|
||||
input +
|
||||
": " +
|
||||
options[input].desc
|
||||
);
|
||||
});
|
||||
|
||||
if (program.config) {
|
||||
try {
|
||||
var config = JSON.parse(program.config);
|
||||
console.log(`The parsed options object: `, config);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"\x1b[31m%s\x1b[0m",
|
||||
`Options(Config) is not a not valid JSON Fallback activate`
|
||||
);
|
||||
program.config = false;
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
if (program.config && utils.validateConfig(config, options)) {
|
||||
console.log("Now using Options object");
|
||||
Object.keys(options).forEach(function(input) {
|
||||
options[input] = config[input];
|
||||
});
|
||||
} else {
|
||||
// If inputs exist, iterate through them and prompt for values.
|
||||
Object.keys(options).forEach(function(input) {
|
||||
var value = readlineSync.question(
|
||||
"[" +
|
||||
step +
|
||||
"]: Enter a value for " +
|
||||
input +
|
||||
" (" +
|
||||
options[input].type +
|
||||
", default: " +
|
||||
options[input].default +
|
||||
"): "
|
||||
);
|
||||
options[input] = value;
|
||||
});
|
||||
}
|
||||
// Add the step and its inputs to the sequencer.
|
||||
sequencer.addSteps(step, options);
|
||||
});
|
||||
|
||||
var spinnerObj = { succeed: () => { }, stop: () => { } };
|
||||
if (!process.env.TEST)
|
||||
spinnerObj = Spinner("Your Image is being processed..").start();
|
||||
|
||||
// Run the sequencer.
|
||||
sequencer.run({ progressObj: spinnerObj }, function() {
|
||||
// Export all images or final image as binary files.
|
||||
sequencer.exportBin(program.output, program.basic, outputFilename);
|
||||
|
||||
//check if spinner was not overriden stop it
|
||||
if (!spinnerObj.overrideFlag) {
|
||||
spinnerObj.succeed();
|
||||
console.log(`\nDone!!`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -24,6 +24,12 @@ module.exports = function Dynamic(options, UI, util) {
|
||||
// save first image's pixels
|
||||
var priorStep = this.getStep(options.offset);
|
||||
|
||||
if (priorStep.output === undefined) {
|
||||
this.output = input;
|
||||
UI.notify('Offset Unavailable','offset-notification');
|
||||
callback();
|
||||
}
|
||||
|
||||
getPixels(priorStep.output.src, function(err, pixels) {
|
||||
options.firstImagePixels = pixels;
|
||||
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
|
||||
module.exports = function Brightness(options,UI){
|
||||
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
options.brightness = parseInt(options.brightness) || 100;
|
||||
var val = (options.brightness)/100.0;
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
@@ -20,13 +23,10 @@ module.exports = function Brightness(options,UI){
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a){
|
||||
options.brightness =
|
||||
options.brightness || 100
|
||||
var val = (options.brightness)/100.0
|
||||
|
||||
r = val*r<255?val*r:255
|
||||
g = val*g<255?val*g:255
|
||||
b = val*b<255?val*b:255
|
||||
r = Math.min(val*r, 255)
|
||||
g = Math.min(val*g, 255)
|
||||
b = Math.min(val*b, 255)
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"brightness": {
|
||||
"type": "range",
|
||||
"desc": "% brightness for the new image",
|
||||
"default": "100",
|
||||
"default": "175",
|
||||
"min": "0",
|
||||
"max": "200",
|
||||
"step": "1"
|
||||
|
||||
@@ -53,7 +53,7 @@ function colormap(segments) {
|
||||
|
||||
var colormaps = {
|
||||
greyscale: colormap([
|
||||
[0, [0, 0, 0], [220, 20, 60] ],
|
||||
[0, [0, 0, 0], [255, 255, 255] ],
|
||||
[1, [255, 255, 255], [255, 255, 255] ]
|
||||
]),
|
||||
|
||||
@@ -177,7 +177,7 @@ var colormaps = {
|
||||
fastie: colormap([
|
||||
[0, [255, 255, 255], [0, 0, 0] ],
|
||||
[0.167, [0, 0, 0], [255, 255, 255] ],
|
||||
[0.33, [2, 0, 226], [2, 0, 226] ],
|
||||
[0.33, [255, 255, 255], [0, 0, 0] ],
|
||||
[0.5, [0, 0, 0], [140, 140, 255] ],
|
||||
[0.55, [140, 140, 255], [0, 255, 0] ],
|
||||
[0.63, [0, 255, 0], [255, 255, 0] ],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"type": "select",
|
||||
"desc": "Name of the Colormap",
|
||||
"default": "default",
|
||||
"values": ["default","greyscale","stretched","fastie","brntogrn","blutoredjet","colors16"]
|
||||
"values": ["default","greyscale","bluwhtgrngis","stretched","fastie","brntogrn","blutoredjet","colors16"]
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
"description": "Change the contrast of the image by given value",
|
||||
"inputs": {
|
||||
"contrast": {
|
||||
"type": "Number",
|
||||
"type": "range",
|
||||
"desc": "contrast for the new image, typically -100 to 100",
|
||||
"default": 70
|
||||
"default": "70",
|
||||
"min": "-100",
|
||||
"max": "100",
|
||||
"step": "1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
|
||||
@@ -9,14 +9,25 @@ module.exports = function Crop(input,options,callback) {
|
||||
getPixels(input.src,function(err,pixels){
|
||||
options.w = parseInt(options.w) || Math.floor(pixels.shape[0]);
|
||||
options.h = parseInt(options.h) || Math.floor(pixels.shape[1]);
|
||||
options.backgroundColor = options.backgroundColor || '255 255 255 255';
|
||||
var ox = options.x;
|
||||
var oy = options.y;
|
||||
var w = options.w;
|
||||
var h = options.h;
|
||||
var iw = pixels.shape[0]; //Width of Original Image
|
||||
var ih = pixels.shape[1]; //Height of Original Image
|
||||
var backgroundArray = [];
|
||||
backgroundColor = options.backgroundColor.split(" ");
|
||||
for(var i = 0; i < w ; i++){
|
||||
backgroundArray = backgroundArray.concat([backgroundColor[0],backgroundColor[1],backgroundColor[2],backgroundColor[3]]);
|
||||
}
|
||||
var newarray = new Uint8Array(4*w*h);
|
||||
for (var n = oy; n < oy + h; n++) {
|
||||
if(n<ih){
|
||||
newarray.set(pixels.data.slice(n*4*iw + ox, n*4*iw + ox + 4*w),4*w*(n-oy));
|
||||
} else {
|
||||
newarray.set(backgroundArray,4*w*(n-oy));
|
||||
}
|
||||
}
|
||||
pixels.data = newarray;
|
||||
pixels.shape = [w,h,4];
|
||||
|
||||
@@ -19,7 +19,7 @@ module.exports = function CropModule(options, UI) {
|
||||
// add our custom in-module html ui:
|
||||
if (options.step.inBrowser && !options.noUI) var ui = require('./Ui.js')(options.step, UI);
|
||||
var output,
|
||||
setupComplete = false;
|
||||
setupComplete = false;
|
||||
|
||||
// This function is caled everytime the step has to be redrawn
|
||||
function draw(input,callback) {
|
||||
@@ -29,8 +29,23 @@ module.exports = function CropModule(options, UI) {
|
||||
// save the input image;
|
||||
// TODO: this should be moved to module API to persist the input image
|
||||
options.step.input = input.src;
|
||||
var parseCornerCoordinateInputs = require('../../util/ParseInputCoordinates');
|
||||
|
||||
require('./Crop')(input, options, function(out, format){
|
||||
//parse the inputs
|
||||
parseCornerCoordinateInputs(options,{
|
||||
src: input.src,
|
||||
x: { valInp: options.x, type: 'horizontal' },
|
||||
y: { valInp: options.y, type: 'vertical' },
|
||||
w: { valInp: options.w, type: 'horizontal' },
|
||||
h: { valInp: options.h, type: 'vertical' },
|
||||
}, function (options, coord) {
|
||||
options.x = parseInt(coord.x.valInp);
|
||||
options.y = parseInt(coord.y.valInp);
|
||||
options.w = coord.w.valInp;
|
||||
options.h = coord.h.valInp;
|
||||
});
|
||||
|
||||
require('./Crop')(input, options, function (out, format) {
|
||||
|
||||
// This output is accessible to Image Sequencer
|
||||
step.output = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Crop",
|
||||
"description": "Crop image to given x, y, w, h in pixels, measured from top left",
|
||||
"description": "Crop image to given x, y, w, h in pixels or % , measured from top left",
|
||||
"url": "https://github.com/publiclab/image-sequencer/tree/master/MODULES.md",
|
||||
"inputs": {
|
||||
"x": {
|
||||
@@ -16,13 +16,19 @@
|
||||
"w": {
|
||||
"type": "integer",
|
||||
"desc": "Width of crop",
|
||||
"default": "(100%)"
|
||||
"default": "(50%)"
|
||||
},
|
||||
"h": {
|
||||
"type": "integer",
|
||||
"desc": "Height of crop",
|
||||
"default": "(100%)"
|
||||
"default": "(50%)"
|
||||
},
|
||||
"backgroundColor": {
|
||||
"type": "String",
|
||||
"desc": "Background Color (Four space separated RGBA values)",
|
||||
"default": "255 255 255 255",
|
||||
"placeholder": "255 255 255 255"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
}
|
||||
|
||||
70
src/modules/Dither/Dither.js
Normal file
70
src/modules/Dither/Dither.js
Normal file
@@ -0,0 +1,70 @@
|
||||
module.exports = function Dither(pixels, type) {
|
||||
type = type || "none";
|
||||
var bayerThresholdMap = [
|
||||
[ 15, 135, 45, 165 ],
|
||||
[ 195, 75, 225, 105 ],
|
||||
[ 60, 180, 30, 150 ],
|
||||
[ 240, 120, 210, 90 ]
|
||||
];
|
||||
|
||||
var lumR = [];
|
||||
var lumG = [];
|
||||
var lumB = [];
|
||||
for (var i=0; i<256; i++) {
|
||||
lumR[i] = i*0.299;
|
||||
lumG[i] = i*0.587;
|
||||
lumB[i] = i*0.114;
|
||||
}
|
||||
var threshold = 129;
|
||||
var imageDataLength = pixels.data.length; //imageData.data.length;
|
||||
|
||||
// Greyscale luminance (sets r pixels to luminance of rgb)
|
||||
for (var i = 0; i <= imageDataLength; i += 4) {
|
||||
pixels.data[i] = Math.floor(lumR[pixels.data[i]] + lumG[pixels.data[i+1]] + lumB[pixels.data[i+2]]);
|
||||
}
|
||||
|
||||
var w = pixels.shape[0];
|
||||
var newPixel, err;
|
||||
|
||||
for (var currentPixel = 0; currentPixel <= imageDataLength; currentPixel+=4) {
|
||||
|
||||
if (type === "none") {
|
||||
// No dithering
|
||||
pixels.data[currentPixel] = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||
} else if (type === "bayer") {
|
||||
// 4x4 Bayer ordered dithering algorithm
|
||||
var x = currentPixel/4 % w;
|
||||
var y = Math.floor(currentPixel/4 / w);
|
||||
var map = Math.floor( (pixels.data[currentPixel] + bayerThresholdMap[x%4][y%4]) / 2 );
|
||||
pixels.data[currentPixel] = (map < threshold) ? 0 : 255;
|
||||
} else if (type === "floydsteinberg") {
|
||||
// Floyd–Steinberg dithering algorithm
|
||||
newPixel = pixels.data[currentPixel] < 129 ? 0 : 255;
|
||||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 16);
|
||||
pixels.data[currentPixel] = newPixel;
|
||||
|
||||
pixels.data[currentPixel + 4 ] += err*7;
|
||||
pixels.data[currentPixel + 4*w - 4 ] += err*3;
|
||||
pixels.data[currentPixel + 4*w ] += err*5;
|
||||
pixels.data[currentPixel + 4*w + 4 ] += err*1;
|
||||
} else {
|
||||
// Bill Atkinson's dithering algorithm
|
||||
newPixel = pixels.data[currentPixel] < threshold ? 0 : 255;
|
||||
err = Math.floor((pixels.data[currentPixel] - newPixel) / 8);
|
||||
pixels.data[currentPixel] = newPixel;
|
||||
|
||||
pixels.data[currentPixel + 4 ] += err;
|
||||
pixels.data[currentPixel + 8 ] += err;
|
||||
pixels.data[currentPixel + 4*w - 4 ] += err;
|
||||
pixels.data[currentPixel + 4*w ] += err;
|
||||
pixels.data[currentPixel + 4*w + 4 ] += err;
|
||||
pixels.data[currentPixel + 8*w ] += err;
|
||||
}
|
||||
|
||||
// Set g and b pixels equal to r
|
||||
pixels.data[currentPixel + 1] = pixels.data[currentPixel + 2] = pixels.data[currentPixel];
|
||||
}
|
||||
return pixels;
|
||||
|
||||
}
|
||||
|
||||
37
src/modules/Dither/Module.js
Normal file
37
src/modules/Dither/Module.js
Normal file
@@ -0,0 +1,37 @@
|
||||
module.exports = function Dither(options, UI){
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input,callback,progressObj){
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('./Dither')(pixels, options.dither)
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype){
|
||||
// This output is accessible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
callback: callback
|
||||
});
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/Dither/index.js
Normal file
4
src/modules/Dither/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
13
src/modules/Dither/info.json
Normal file
13
src/modules/Dither/info.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "Dither",
|
||||
"description": "Approximates a color from a mixture of other colors when the required color is not available, creating illusions of the color that is not present actually.<a href='https://en.wikipedia.org/wiki/Dither'>Read more</a>",
|
||||
"inputs": {
|
||||
"dither": {
|
||||
"type": "select",
|
||||
"desc": "Name of the Dithering Algorithm",
|
||||
"default": "none",
|
||||
"values": ["none","floydsteinberg","bayer","Atkinson"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
src/modules/DrawRectangle/DrawRectangle.js
Normal file
37
src/modules/DrawRectangle/DrawRectangle.js
Normal file
@@ -0,0 +1,37 @@
|
||||
module.exports = exports = function(pixels, options){
|
||||
options.startingX = options.startingX || 0;
|
||||
options.startingY = options.startingY || 0;
|
||||
var ox = Number(options.startingX),
|
||||
oy = Number(options.startingY),
|
||||
iw = pixels.shape[0],
|
||||
ih = pixels.shape[1],
|
||||
ex = options.endX = Number(options.endX) || iw - 1,
|
||||
ey = options.endY = Number(options.endY) || ih - 1,
|
||||
thickness = Number(options.thickness) || 1,
|
||||
color = options.color || "0 0 0 255";
|
||||
|
||||
color = color.split(" ");
|
||||
|
||||
var drawSide = function(startY, startX, endY, endX, yIncrement, xIncrement, sign, incrementFactor = 1){
|
||||
for(var i = 0; i<thickness; i++){
|
||||
for(
|
||||
var n = (startY + i*yIncrement*sign)*4*iw + 4*(startX + i*xIncrement*sign);
|
||||
n <= (endY + i*yIncrement*sign)*4*iw + 4*(endX + i*xIncrement*sign);
|
||||
n = n+4*(incrementFactor)
|
||||
)
|
||||
{
|
||||
pixels.data[n] = color[0];
|
||||
pixels.data[n+1] = color[1];
|
||||
pixels.data[n+2] = color[2];
|
||||
pixels.data[n+3] = color[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawSide(oy, ox, oy, ex, 1, 0, 1); // Top
|
||||
drawSide(ey, ox, ey, ex, 1, 0, -1); // Bottom
|
||||
drawSide(oy, ox, ey, ox, 0, 1, 1, iw); // Left
|
||||
drawSide(oy, ex, ey, ex, 0, 1, -1, iw); // Right
|
||||
|
||||
return pixels;
|
||||
}
|
||||
44
src/modules/DrawRectangle/Module.js
Normal file
44
src/modules/DrawRectangle/Module.js
Normal file
@@ -0,0 +1,44 @@
|
||||
module.exports = function DrawRectangle(options, UI) {
|
||||
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
pixels = require('./DrawRectangle')(pixels, options)
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
}
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
4
src/modules/DrawRectangle/index.js
Normal file
4
src/modules/DrawRectangle/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
41
src/modules/DrawRectangle/info.json
Normal file
41
src/modules/DrawRectangle/info.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "Draw Rectangle",
|
||||
"description": "It draws a rectangle on the image",
|
||||
"inputs": {
|
||||
"startingX":{
|
||||
"type": "Number",
|
||||
"desc": "starting x position of the rectangle",
|
||||
"default": 0
|
||||
},
|
||||
|
||||
"startingY": {
|
||||
"type": "Number",
|
||||
"desc": "starting y position of the rectangle",
|
||||
"default": 0
|
||||
},
|
||||
|
||||
"endX":{
|
||||
"type": "integer",
|
||||
"desc": "last x position of the rectangle",
|
||||
"default": "width"
|
||||
},
|
||||
|
||||
"endY":{
|
||||
"type": "integer",
|
||||
"desc": "last y position of the rectangle",
|
||||
"default": "height"
|
||||
},
|
||||
|
||||
"thickness":{
|
||||
"type": "integer",
|
||||
"desc": "thickness of border",
|
||||
"default": 1
|
||||
},
|
||||
|
||||
"color":{
|
||||
"type": "String",
|
||||
"desc": "RGBA values separated by a space",
|
||||
"default": "0 0 0 255"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
{
|
||||
"name": "Detect Edges",
|
||||
"description": "this module detects edges using the Canny method, which first Gaussian blurs the image to reduce noise (amount of blur configurable in settings as `options.blur`), then applies a number of steps to highlight edges, resulting in a greyscale image where the brighter the pixel, the stronger the detected edge.<a href='https://en.wikipedia.org/wiki/Canny_edge_detector'> Read more. </a>",
|
||||
"description": "This module detects edges using the Canny method, which first Gaussian blurs the image to reduce noise (amount of blur configurable in settings as `options.blur`), then applies a number of steps to highlight edges, resulting in a greyscale image where the brighter the pixel, the stronger the detected edge.<a href='https://en.wikipedia.org/wiki/Canny_edge_detector'> Read more. </a>",
|
||||
"inputs": {
|
||||
"blur": {
|
||||
"type": "integer",
|
||||
"desc": "amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||
"default": 2
|
||||
"type": "range",
|
||||
"desc": "Amount of gaussian blur(Less blur gives more detail, typically 0-5)",
|
||||
"default": "2",
|
||||
"min": "0",
|
||||
"max": "5",
|
||||
"step": "0.25"
|
||||
},
|
||||
"highThresholdRatio":{
|
||||
"type": "float",
|
||||
|
||||
@@ -8,8 +8,8 @@ module.exports = function ImportImageModuleUi(step, ui) {
|
||||
|
||||
// add a file input listener
|
||||
var dropZone ='\
|
||||
<div style="padding: 30px;margin: 10px 20% 30px;border: 4px dashed #ccc;border-radius: 8px;text-align: center;color: #444;" id="' + dropzoneId + '">\
|
||||
<p>\
|
||||
<div class="dropzone" style="padding: 30px;margin: 10px 20% 30px;border: 4px dashed #ccc;border-radius: 8px;text-align: center;color: #444;" id="' + dropzoneId + '">\
|
||||
<p>\
|
||||
<i>Select or drag in an image to overlay.</i>\
|
||||
</p>\
|
||||
<center>\
|
||||
|
||||
@@ -15,13 +15,25 @@ module.exports = function Dynamic(options, UI, util) {
|
||||
|
||||
var step = this;
|
||||
|
||||
var parseCornerCoordinateInputs = require('../../util/ParseInputCoordinates');
|
||||
|
||||
//parse the inputs
|
||||
parseCornerCoordinateInputs(options, {
|
||||
src: input.src,
|
||||
x: { valInp: options.x, type: 'horizontal' },
|
||||
y: { valInp: options.y, type: 'vertical' },
|
||||
}, function (options, input) {
|
||||
options.x = parseInt(input.x.valInp);
|
||||
options.y = parseInt(input.y.valInp);
|
||||
});
|
||||
|
||||
// save the pixels of the base image
|
||||
var baseStepImage = this.getStep(options.offset).image;
|
||||
var baseStepOutput = this.getOutput(options.offset);
|
||||
|
||||
var getPixels = require('get-pixels');
|
||||
|
||||
getPixels(input.src, function(err, pixels) {
|
||||
getPixels(input.src, function (err, pixels) {
|
||||
options.secondImagePixels = pixels;
|
||||
|
||||
function changePixel(r1, g1, b1, a1, x, y) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Overlay",
|
||||
"description": "Overlays an Image over another at a given position(x,y)",
|
||||
"description": "Overlays an Image over another at a given position(x,y) in pixels or in %",
|
||||
"inputs": {
|
||||
"x": {
|
||||
"type": "integer",
|
||||
|
||||
47
src/modules/PaintBucket/Module.js
Normal file
47
src/modules/PaintBucket/Module.js
Normal file
@@ -0,0 +1,47 @@
|
||||
module.exports = function PaintBucket(options, UI) {
|
||||
|
||||
var output;
|
||||
|
||||
function draw(input, callback, progressObj) {
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b, a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
|
||||
|
||||
pixels = require('./PaintBucket')(pixels, options)
|
||||
return pixels
|
||||
|
||||
}
|
||||
|
||||
function output(image, datauri, mimetype) {
|
||||
// This output is accesible by Image Sequencer
|
||||
step.output = { src: datauri, format: mimetype };
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
}
|
||||
64
src/modules/PaintBucket/PaintBucket.js
Normal file
64
src/modules/PaintBucket/PaintBucket.js
Normal file
@@ -0,0 +1,64 @@
|
||||
module.exports = exports = function(pixels, options){
|
||||
|
||||
var fillColor = options.fillColor || '100 100 100 255',
|
||||
x = parseInt(options.startingX) || 10,
|
||||
y = parseInt(options.startingY) || 10,
|
||||
height = pixels.shape[1],
|
||||
width = pixels.shape[0],
|
||||
r = pixels.get(x, y, 0),
|
||||
g = pixels.get(x,y,1),
|
||||
b = pixels.get(x,y,2),
|
||||
a = pixels.get(x, y, 3),
|
||||
queuex = [x],
|
||||
queuey = [y],
|
||||
curry, currx,
|
||||
north,
|
||||
south,
|
||||
n,
|
||||
tolerance = parseInt(options.tolerance) || 10,
|
||||
maxFactor = (1 + tolerance/100),
|
||||
minFactor = (1 - tolerance/100);
|
||||
|
||||
fillColor = fillColor.split(" ");
|
||||
function isSimilar(currx, curry){
|
||||
return (pixels.get(currx, curry, 0) > r*minFactor && pixels.get(currx, curry, 0) < r*maxFactor &&
|
||||
pixels.get(currx, curry, 1) > g*minFactor && pixels.get(currx, curry, 1) < g*maxFactor &&
|
||||
pixels.get(currx, curry, 2) > b*minFactor && pixels.get(currx, curry, 2) < b*maxFactor &&
|
||||
pixels.get(currx, curry, 3) > a*minFactor && pixels.get(currx, curry, 3) < a*maxFactor);
|
||||
}
|
||||
|
||||
while (queuey.length) {
|
||||
currx = queuex.pop()
|
||||
curry = queuey.pop()
|
||||
|
||||
|
||||
if (isSimilar(currx, curry)) {
|
||||
north = south = curry
|
||||
|
||||
do {
|
||||
north -= 1
|
||||
} while (isSimilar(currx, north) && north >= 0)
|
||||
|
||||
do {
|
||||
south += 1
|
||||
} while (isSimilar(currx, south) && south < height)
|
||||
|
||||
for (n = north + 1; n < south; n += 1) {
|
||||
pixels.set(currx, n, 0, fillColor[0]);
|
||||
pixels.set(currx, n, 1, fillColor[1]);
|
||||
pixels.set(currx, n, 2, fillColor[2]);
|
||||
pixels.set(currx, n, 3, fillColor[3]);
|
||||
if (isSimilar(currx - 1, n)) {
|
||||
queuex.push(currx - 1)
|
||||
queuey.push(n)
|
||||
}
|
||||
if (isSimilar(currx + 1, n)) {
|
||||
queuex.push(currx + 1)
|
||||
queuey.push(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pixels;
|
||||
}
|
||||
4
src/modules/PaintBucket/index.js
Normal file
4
src/modules/PaintBucket/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
30
src/modules/PaintBucket/info.json
Normal file
30
src/modules/PaintBucket/info.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "PaintBucket",
|
||||
"description": "Fill color in pixels",
|
||||
"inputs": {
|
||||
"startingX": {
|
||||
"type": "integer",
|
||||
"desc": "value of the starting x-coordinate",
|
||||
"default": "10"
|
||||
},
|
||||
"startingY": {
|
||||
"type": "integer",
|
||||
"desc": "value of the starting y-coordinate",
|
||||
"default": "10"
|
||||
},
|
||||
"fillColor": {
|
||||
"type": "String",
|
||||
"desc": "four space separated numbers representing the RGBA values of fill-color",
|
||||
"default": "100 100 100 255",
|
||||
"placeholder": "100 100 100 255"
|
||||
},
|
||||
"tolerance": {
|
||||
"type": "range",
|
||||
"desc": "% tolerance",
|
||||
"default": "10",
|
||||
"min": "5",
|
||||
"max": "15",
|
||||
"step": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,12 @@
|
||||
"description": "Rotates image by specified degrees",
|
||||
"inputs": {
|
||||
"rotate": {
|
||||
"type": "integer",
|
||||
"type": "range",
|
||||
"desc": "Angular value for rotation in degrees",
|
||||
"default": 0
|
||||
"default": "0",
|
||||
"min": "0",
|
||||
"max": "360",
|
||||
"step": "1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
"description": "Change the saturation of the image by given value, from 0-1, with 1 being 100% saturated.",
|
||||
"inputs": {
|
||||
"saturation": {
|
||||
"type": "integer",
|
||||
"type": "range",
|
||||
"desc": "saturation for the new image between 0 and 2, 0 being black and white and 2 being highly saturated",
|
||||
"default": 0
|
||||
"default": "0.5",
|
||||
"min": "0",
|
||||
"max": "2",
|
||||
"step": "0.1"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
|
||||
86
src/modules/WhiteBalance/Module.js
Normal file
86
src/modules/WhiteBalance/Module.js
Normal file
@@ -0,0 +1,86 @@
|
||||
module.exports = function Balance(options, UI) {
|
||||
|
||||
var output;
|
||||
|
||||
function draw (input, callback, progressObj) {
|
||||
|
||||
options.temperature = (options.temperature > "40000") ? "40000" : options.temperature
|
||||
|
||||
progressObj.stop(true);
|
||||
progressObj.overrideFlag = true;
|
||||
|
||||
var step = this;
|
||||
|
||||
function changePixel(r, g, b, a) {
|
||||
return [r, g, b ,a]
|
||||
}
|
||||
|
||||
function extraManipulation(pixels) {
|
||||
|
||||
let temp = parseInt(options.temperature)
|
||||
temp /= 100
|
||||
|
||||
let r, g, b;
|
||||
|
||||
if (temp <= 66) {
|
||||
r = 255;
|
||||
g = Math.min(Math.max(99.4708025861 * Math.log(temp) - 161.1195681661, 0), 255);
|
||||
} else {
|
||||
r = Math.min(Math.max(329.698727446 * Math.pow(temp - 60, -0.1332047592), 0), 255);
|
||||
g = Math.min(Math.max(288.1221695283 * Math.pow(temp - 60, -0.0755148492), 0), 255);
|
||||
}
|
||||
|
||||
if (temp >= 66) {
|
||||
b = 255;
|
||||
} else if (temp <= 19) {
|
||||
b = 0;
|
||||
} else {
|
||||
b = temp - 10;
|
||||
b = Math.min(Math.max(138.5177312231 * Math.log(b) - 305.0447927307, 0), 255);
|
||||
}
|
||||
|
||||
for(let i=0; i<pixels.shape[0]; i++) {
|
||||
for (let j=0; j<pixels.shape[1]; j++) {
|
||||
|
||||
r_data = pixels.get(i,j,0)
|
||||
r_new_data = (255/r) * r_data
|
||||
pixels.set(i,j,0,r_new_data)
|
||||
|
||||
g_data = pixels.get(i,j,1)
|
||||
g_new_data = (255/g) * g_data
|
||||
pixels.set(i,j,1,g_new_data)
|
||||
|
||||
b_data = pixels.get(i,j,2)
|
||||
b_new_data = (255/b) * b_data
|
||||
pixels.set(i,j,2,b_new_data)
|
||||
}
|
||||
}
|
||||
|
||||
return pixels
|
||||
}
|
||||
|
||||
function output (image, datauri, mimetype){
|
||||
|
||||
step.output = {src:datauri,format:mimetype};
|
||||
|
||||
}
|
||||
|
||||
return require('../_nomodule/PixelManipulation.js')(input, {
|
||||
output: output,
|
||||
changePixel: changePixel,
|
||||
extraManipulation: extraManipulation,
|
||||
format: input.format,
|
||||
image: options.image,
|
||||
inBrowser: options.inBrowser,
|
||||
callback: callback
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
options: options,
|
||||
draw: draw,
|
||||
output: output,
|
||||
UI: UI
|
||||
}
|
||||
|
||||
}
|
||||
4
src/modules/WhiteBalance/index.js
Normal file
4
src/modules/WhiteBalance/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
module.exports = [
|
||||
require('./Module'),
|
||||
require('./info.json')
|
||||
]
|
||||
12
src/modules/WhiteBalance/info.json
Normal file
12
src/modules/WhiteBalance/info.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "White Balance",
|
||||
"description": "Change the colour balance of the image by adjusting the colour temperature.",
|
||||
"inputs": {
|
||||
"temperature": {
|
||||
"type": "string",
|
||||
"desc": "Temperature between 0 - 40,000 Kelvin",
|
||||
"default": "6000"
|
||||
}
|
||||
},
|
||||
"docs-link":"https://github.com/publiclab/image-sequencer/blob/main/docs/MODULES.md"
|
||||
}
|
||||
@@ -39,23 +39,23 @@ function setInputStepInit() {
|
||||
context = canvas.getContext('2d'),
|
||||
vendorUrl = window.URL || window.webkitURL;
|
||||
|
||||
navigator.getMedia = navigator.getUserMedia || navigator.wekitGetUserMedia ||
|
||||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
const constraints = { audio: false,video: true};
|
||||
|
||||
navigator.getMedia({
|
||||
video: true,
|
||||
audio: false
|
||||
}, function(stream){ // success callback
|
||||
video.srcObject = stream;
|
||||
video.onloadedmetadata = function(e) {
|
||||
video.play();
|
||||
};
|
||||
document.getElementById('close').addEventListener('click', function () {
|
||||
stopStream(stream);
|
||||
});
|
||||
}, function(error){ // error
|
||||
console.log("error");
|
||||
});
|
||||
function handleSuccess(stream) {
|
||||
window.stream = stream; // make stream available to browser console
|
||||
video.srcObject = stream;
|
||||
video.onloadedmetadata = function(e) {
|
||||
video.play();
|
||||
};
|
||||
document.getElementById('close').addEventListener('click', function () {
|
||||
stopStream(stream);
|
||||
});
|
||||
}
|
||||
function handleError(error) {
|
||||
console.log('navigator.getUserMedia error: ', error);
|
||||
}
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError);
|
||||
|
||||
|
||||
document.getElementById('capture').addEventListener('click', function(stream){
|
||||
context.drawImage(video, 0, 0, 400, 300);
|
||||
|
||||
@@ -53,6 +53,10 @@ module.exports = function UserInterface(events = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
events.notify = events.notify || function(msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
return events;
|
||||
|
||||
}
|
||||
|
||||
24
src/util/ParseInputCoordinates.js
Normal file
24
src/util/ParseInputCoordinates.js
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = function parseCornerCoordinateInputs(options,coord,callback) {
|
||||
var getPixels = require('get-pixels');
|
||||
getPixels(coord.src, function(err, pixels) {
|
||||
var iw = pixels.shape[0],
|
||||
ih = pixels.shape[1];
|
||||
if (!coord.x.valInp) {
|
||||
return
|
||||
}
|
||||
else {
|
||||
Object.keys(coord).forEach(convert);
|
||||
function convert(key) {
|
||||
var val = coord[key];
|
||||
if (val.valInp && val.valInp.slice(-1) === "%") {
|
||||
val.valInp = parseInt(val.valInp, 10);
|
||||
if (val.type === 'horizontal')
|
||||
val.valInp = val.valInp * iw / 100;
|
||||
else
|
||||
val.valInp = val.valInp * ih / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(options, coord);
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const cliUtils = require('../src/CliUtils');
|
||||
const cliUtils = require('../../src/CliUtils');
|
||||
const test = require('tape');
|
||||
|
||||
test('Output directory is correctly generated',function(t){
|
||||
22
test/core/modules/brightness.js
Normal file
22
test/core/modules/brightness.js
Normal file
@@ -0,0 +1,22 @@
|
||||
var test = require('tape');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer1 = ImageSequencer({ ui: false });
|
||||
var options = {brightness : 50};
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
|
||||
// Test 1 to check brightness module is getting loaded
|
||||
test('Load brightness module', function(t) {
|
||||
sequencer1.loadImages('image1', red);
|
||||
sequencer1.addSteps('brightness', options);
|
||||
t.equal(sequencer1.images.image1.steps[1].options.name, "brightness", "Brightness module is getting loaded.");
|
||||
t.end();
|
||||
});
|
||||
|
||||
// Test 2 to check options are correct
|
||||
test('Check Options', function(t) {
|
||||
sequencer1.loadImages('image1', red);
|
||||
sequencer1.addSteps('brightness', options);
|
||||
t.equal(sequencer1.images.image1.steps[1].options.brightness, 50, "Options are correct");
|
||||
t.end();
|
||||
});
|
||||
@@ -6,7 +6,7 @@ var test = require('tape');
|
||||
// We should only test headless code here.
|
||||
// http://stackoverflow.com/questions/21358015/error-jquery-requires-a-window-with-a-document#25622933
|
||||
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
@@ -1,5 +1,5 @@
|
||||
var test = require('tape');
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
@@ -7,7 +7,7 @@ var DataURItoBuffer = require('data-uri-to-buffer');
|
||||
// We should only test headless code here.
|
||||
// http://stackoverflow.com/questions/21358015/error-jquery-requires-a-window-with-a-document#25622933
|
||||
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
//require image files as DataURLs so they can be tested alike on browser and Node.
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
@@ -6,7 +6,7 @@ var test = require('tape');
|
||||
// We should only test headless code here.
|
||||
// http://stackoverflow.com/questions/21358015/error-jquery-requires-a-window-with-a-document#25622933
|
||||
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
// This function is used to test whether or not any additional global variables are being created
|
||||
function copy(g, a) {
|
||||
@@ -1,5 +1,5 @@
|
||||
var test = require('tape');
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
@@ -1,5 +1,5 @@
|
||||
var test = require('tape');
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer1 = ImageSequencer({ ui: false });
|
||||
var sequencer2 = ImageSequencer({ ui: false });
|
||||
@@ -3,7 +3,7 @@
|
||||
var fs = require('fs');
|
||||
var test = require('tape');
|
||||
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
@@ -4,7 +4,7 @@ var fs = require('fs');
|
||||
var test = require('tape');
|
||||
var DataURItoBuffer = require('data-uri-to-buffer');
|
||||
|
||||
require('../../src/ImageSequencer.js');
|
||||
require('../../../src/ImageSequencer.js');
|
||||
|
||||
var sequencer = ImageSequencer({ ui: false });
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
31
test/core/ui/user-interface.js
Normal file
31
test/core/ui/user-interface.js
Normal file
@@ -0,0 +1,31 @@
|
||||
var test = require('tape');
|
||||
var jsdom = require('jsdom');
|
||||
var JSDOM = jsdom.JSDOM;
|
||||
|
||||
var DOM = new JSDOM(`<body></body>`);
|
||||
|
||||
global.document = DOM.window.document;
|
||||
|
||||
var DefaultHtmlStepUi = require('../../../examples/lib/defaultHtmlStepUi')
|
||||
var sequencer = require('../../../src/ImageSequencer.js')();
|
||||
var UserInterface = require('../../../src/ui/UserInterface');
|
||||
|
||||
test('Notify function works for all three UIs', function (t) {
|
||||
//Mocking console.log for testing default notify()
|
||||
function doesLogMessage(f, message) {
|
||||
var oldLog = console.log,
|
||||
result = false;
|
||||
console.log = function (s) {
|
||||
if (s == message) {
|
||||
result = true;
|
||||
}
|
||||
};
|
||||
f('Test Message');
|
||||
console.log = oldLog;
|
||||
return result;
|
||||
}
|
||||
t.equal(doesLogMessage(UserInterface().notify, 'Test Message'),true,'Default notify() produces correct output');
|
||||
sequencer.setUI(DefaultHtmlStepUi(sequencer));
|
||||
t.equal(typeof sequencer.events.notify, "function", "Html UI contains notify function");
|
||||
t.end();
|
||||
});
|
||||
17
test/core/util/parse-input.js
Normal file
17
test/core/util/parse-input.js
Normal file
@@ -0,0 +1,17 @@
|
||||
var test = require('tape');
|
||||
|
||||
var red = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAAQABADASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgj/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABykX//Z";
|
||||
|
||||
var parseCornerCoordinateInputs = require('../../../src/util/ParseInputCoordinates');
|
||||
|
||||
|
||||
test('parseCornerCoordinateInputs works.', function (t) {
|
||||
var options = { x: '10%' },
|
||||
coord = { src: red, x: { valInp: options.x, type: 'horizontal' } }
|
||||
callback = function (options, coord) {
|
||||
options.x = parseInt(coord.x.valInp);
|
||||
t.equal(options.x, 1, 'parseCornerCoordinateInputs works.');
|
||||
t.end();
|
||||
};
|
||||
parseCornerCoordinateInputs(options, coord, callback);
|
||||
});
|
||||
42
test/spec/defaultHtmlSequencerUi.spec.js
Normal file
42
test/spec/defaultHtmlSequencerUi.spec.js
Normal file
@@ -0,0 +1,42 @@
|
||||
describe('Default sequencer HTML', function() {
|
||||
|
||||
var DefaultHtmlSequencerUi = require('../../examples/lib/defaultHtmlSequencerUi')
|
||||
var sequencer = require('../../src/ImageSequencer')()
|
||||
var defaultHtmlSequencerUi;
|
||||
|
||||
beforeEach(()=>{
|
||||
defaultHtmlSequencerUi = new DefaultHtmlSequencerUi(sequencer)
|
||||
|
||||
spyOn(defaultHtmlSequencerUi,'onLoad')
|
||||
spyOn(defaultHtmlSequencerUi,'selectNewStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'removeStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'addStepUi')
|
||||
spyOn(defaultHtmlSequencerUi,'importStepsFromUrlHash')
|
||||
|
||||
defaultHtmlSequencerUi.onLoad()
|
||||
defaultHtmlSequencerUi.selectNewStepUi()
|
||||
defaultHtmlSequencerUi.addStepUi()
|
||||
defaultHtmlSequencerUi.removeStepUi()
|
||||
defaultHtmlSequencerUi.importStepsFromUrlHash()
|
||||
})
|
||||
|
||||
it('load default ui', function() {
|
||||
expect(defaultHtmlSequencerUi.onLoad).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('select step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.selectNewStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('add step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.addStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('remove step ui', function() {
|
||||
expect(defaultHtmlSequencerUi.removeStepUi).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('import options from url', function() {
|
||||
expect(defaultHtmlSequencerUi.importStepsFromUrlHash).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
61
test/spec/defaultHtmlStepUi.spec.js
Normal file
61
test/spec/defaultHtmlStepUi.spec.js
Normal file
@@ -0,0 +1,61 @@
|
||||
var { JSDOM } = require('jsdom');
|
||||
var DOM = new JSDOM(`<body></body>`);
|
||||
|
||||
global.document = DOM.window.document;
|
||||
|
||||
describe('Sequencer step HTML', function() {
|
||||
|
||||
var DefaultHtmlStepUi = require('../../examples/lib/defaultHtmlStepUi')
|
||||
var sequencer = require('../../src/ImageSequencer')()
|
||||
var defaultHtmlStepUi;
|
||||
var step = 'brightness'
|
||||
var options = {
|
||||
name: "Brightness",
|
||||
description: "Change the brightness of the image by given percent value"
|
||||
}
|
||||
// options = JSON.parse(options)
|
||||
|
||||
beforeEach(()=>{
|
||||
defaultHtmlStepUi = new DefaultHtmlStepUi(sequencer)
|
||||
|
||||
spyOn(defaultHtmlStepUi,'getPreview')
|
||||
spyOn(defaultHtmlStepUi,'onSetup')
|
||||
spyOn(defaultHtmlStepUi,'onComplete')
|
||||
spyOn(defaultHtmlStepUi,'onDraw')
|
||||
spyOn(defaultHtmlStepUi,'onRemove')
|
||||
spyOn(defaultHtmlStepUi,'notify')
|
||||
|
||||
defaultHtmlStepUi.getPreview()
|
||||
defaultHtmlStepUi.onSetup(step,options)
|
||||
defaultHtmlStepUi.onComplete(step)
|
||||
defaultHtmlStepUi.onDraw(step)
|
||||
defaultHtmlStepUi.onRemove(step)
|
||||
defaultHtmlStepUi.notify('Step removed','remove-notification')
|
||||
})
|
||||
|
||||
|
||||
it('result preview ui', function() {
|
||||
expect(defaultHtmlStepUi.getPreview).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('load initial setup ui', function() {
|
||||
expect(defaultHtmlStepUi.onSetup).toHaveBeenCalledWith(step,options)
|
||||
})
|
||||
|
||||
it('load completion ui', function() {
|
||||
expect(defaultHtmlStepUi.onComplete).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('draw step ui', function() {
|
||||
expect(defaultHtmlStepUi.onDraw).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('remove step ui', function() {
|
||||
expect(defaultHtmlStepUi.onRemove).toHaveBeenCalledWith(step)
|
||||
})
|
||||
|
||||
it('notification ui', function() {
|
||||
expect(defaultHtmlStepUi.notify).toHaveBeenCalledWith('Step removed','remove-notification')
|
||||
})
|
||||
|
||||
})
|
||||
8
test/spec/helpers/reporter.js
Normal file
8
test/spec/helpers/reporter.js
Normal file
@@ -0,0 +1,8 @@
|
||||
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||
|
||||
jasmine.getEnv().clearReporters(); // remove default reporter logs
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ // add jasmine-spec-reporter
|
||||
spec: {
|
||||
displayPending: true
|
||||
}
|
||||
}));
|
||||
26
test/spec/insertPreview.spec.js
Normal file
26
test/spec/insertPreview.spec.js
Normal file
@@ -0,0 +1,26 @@
|
||||
describe('Preview UI HTML', function() {
|
||||
|
||||
var InsertPreview = require('../../examples/lib/insertPreview')
|
||||
var sequencer = require('../../src/ImageSequencer')()
|
||||
var insertPreview;
|
||||
var options = { brightness: 50 }
|
||||
|
||||
beforeEach(()=>{
|
||||
insertPreview = InsertPreview
|
||||
|
||||
spyOn(insertPreview,'generatePreview')
|
||||
spyOn(insertPreview,'updatePreviews')
|
||||
|
||||
insertPreview.generatePreview('brightness',options,'src','selector')
|
||||
insertPreview.updatePreviews('src','selector')
|
||||
})
|
||||
|
||||
it('generate preview ui', function() {
|
||||
expect(insertPreview.generatePreview).toHaveBeenCalledWith('brightness',options,'src','selector')
|
||||
})
|
||||
|
||||
it('update preview ui', function() {
|
||||
expect(insertPreview.updatePreviews).toHaveBeenCalledWith('src','selector')
|
||||
})
|
||||
|
||||
})
|
||||
19
test/spec/intermediateHtmlStepUi.spec.js
Normal file
19
test/spec/intermediateHtmlStepUi.spec.js
Normal file
@@ -0,0 +1,19 @@
|
||||
describe('Intermediate step HTML', function() {
|
||||
|
||||
var IntermediateHtmlStepUi = require('../../examples/lib/intermediateHtmlStepUi')
|
||||
var sequencer = require('../../src/ImageSequencer')()
|
||||
var intermediateHtmlStepUi;
|
||||
|
||||
beforeEach(()=>{
|
||||
intermediateHtmlStepUi = new IntermediateHtmlStepUi(sequencer)
|
||||
|
||||
spyOn(intermediateHtmlStepUi,'insertStep')
|
||||
|
||||
intermediateHtmlStepUi.insertStep()
|
||||
})
|
||||
|
||||
it('insert step ui', function() {
|
||||
expect(intermediateHtmlStepUi.insertStep).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
})
|
||||
11
test/spec/support/jasmine.json
Normal file
11
test/spec/support/jasmine.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"spec_dir": "test/spec",
|
||||
"spec_files": [
|
||||
"**/*.[sS]pec.js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.js"
|
||||
],
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": false
|
||||
}
|
||||
40
test/spec/urlHash.spec.js
Normal file
40
test/spec/urlHash.spec.js
Normal file
@@ -0,0 +1,40 @@
|
||||
describe('URL manipulation methods', function() {
|
||||
|
||||
var UrlHash = require('../../examples/lib/urlHash')
|
||||
var urlHash;
|
||||
var params = {
|
||||
module: 'brightness',
|
||||
brightness: 50
|
||||
}
|
||||
|
||||
beforeEach(()=>{
|
||||
urlHash = UrlHash
|
||||
|
||||
spyOn(urlHash,'getUrlHashParameters')
|
||||
spyOn(urlHash,'getUrlHashParameter')
|
||||
spyOn(urlHash,'setUrlHashParameters')
|
||||
spyOn(urlHash,'setUrlHashParameter')
|
||||
|
||||
urlHash.getUrlHashParameters()
|
||||
urlHash.getUrlHashParameter('module')
|
||||
urlHash.setUrlHashParameters(params)
|
||||
urlHash.setUrlHashParameter('module','brightness')
|
||||
})
|
||||
|
||||
it('gets url hash params from window hash', function() {
|
||||
expect(urlHash.getUrlHashParameters).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('gets url hash param from params object', function() {
|
||||
expect(urlHash.getUrlHashParameter).toHaveBeenCalledWith('module')
|
||||
})
|
||||
|
||||
it('accepts param object and sets url hash params', function() {
|
||||
expect(urlHash.setUrlHashParameters).toHaveBeenCalledWith(params)
|
||||
})
|
||||
|
||||
it('accepts param key-value pair and sets url hash params', function() {
|
||||
expect(urlHash.setUrlHashParameter).toHaveBeenCalledWith('module','brightness')
|
||||
})
|
||||
|
||||
})
|
||||
286
yarn.lock
286
yarn.lock
@@ -32,6 +32,11 @@ JSONStream@^1.0.3:
|
||||
jsonparse "^1.2.0"
|
||||
through ">=2.2.7 <3"
|
||||
|
||||
abab@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f"
|
||||
integrity sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
@@ -45,6 +50,14 @@ accepts@~1.3.4:
|
||||
mime-types "~2.1.18"
|
||||
negotiator "0.6.1"
|
||||
|
||||
acorn-globals@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.0.tgz#e3b6f8da3c1552a95ae627571f7dd6923bb54103"
|
||||
integrity sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==
|
||||
dependencies:
|
||||
acorn "^6.0.1"
|
||||
acorn-walk "^6.0.1"
|
||||
|
||||
acorn-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.6.0.tgz#725c6b8b432451383b5d2816a18a5ab13288aa58"
|
||||
@@ -64,10 +77,10 @@ acorn@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||
|
||||
acorn@^6.0.1:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.2.tgz#6a459041c320ab17592c6317abbfdf4bbaa98ca4"
|
||||
integrity sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg==
|
||||
acorn@^6.0.1, acorn@^6.0.4:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.5.tgz#81730c0815f3f3b34d8efa95cb7430965f4d887a"
|
||||
integrity sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==
|
||||
|
||||
after@0.8.2:
|
||||
version "0.8.2"
|
||||
@@ -178,6 +191,11 @@ arr-union@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
|
||||
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
|
||||
|
||||
array-equal@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
|
||||
integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
|
||||
|
||||
array-filter@~0.0.0:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
|
||||
@@ -469,6 +487,11 @@ browser-pack@^6.0.1:
|
||||
through2 "^2.0.0"
|
||||
umd "^3.0.0"
|
||||
|
||||
browser-process-hrtime@^0.1.2:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz#616f00faef1df7ec1b5bf9cfe2bdc3170f26c7b4"
|
||||
integrity sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==
|
||||
|
||||
browser-resolve@^1.11.0, browser-resolve@^1.7.0:
|
||||
version "1.11.3"
|
||||
resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6"
|
||||
@@ -1180,6 +1203,18 @@ cssauron@^1.1.0:
|
||||
dependencies:
|
||||
through X.X.X
|
||||
|
||||
cssom@0.3.x, cssom@^0.3.4:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797"
|
||||
integrity sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==
|
||||
|
||||
cssstyle@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.1.1.tgz#18b038a9c44d65f7a8e428a653b9f6fe42faf5fb"
|
||||
integrity sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==
|
||||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
currently-unhandled@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||
@@ -1238,6 +1273,15 @@ data-uri-to-buffer@^2.0.0:
|
||||
dependencies:
|
||||
"@types/node" "^8.0.7"
|
||||
|
||||
data-urls@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe"
|
||||
integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==
|
||||
dependencies:
|
||||
abab "^2.0.0"
|
||||
whatwg-mimetype "^2.2.0"
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
date-now@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
|
||||
@@ -1422,6 +1466,13 @@ domain-browser@^1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
||||
integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
|
||||
|
||||
domexception@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
|
||||
integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
|
||||
dependencies:
|
||||
webidl-conversions "^4.0.2"
|
||||
|
||||
downloadjs@^1.4.7:
|
||||
version "1.4.7"
|
||||
resolved "https://registry.yarnpkg.com/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c"
|
||||
@@ -1703,7 +1754,7 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
escodegen@^1.8.1:
|
||||
escodegen@^1.11.0, escodegen@^1.8.1:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589"
|
||||
integrity sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw==
|
||||
@@ -2254,6 +2305,11 @@ gif-encoder@~0.4.1:
|
||||
dependencies:
|
||||
readable-stream "~1.1.9"
|
||||
|
||||
gifshot@^0.4.5:
|
||||
version "0.4.5"
|
||||
resolved "https://registry.yarnpkg.com/gifshot/-/gifshot-0.4.5.tgz#e3cb570203a3b139ff3069d7578098a29c03b0f8"
|
||||
integrity sha1-48tXAgOjsTn/MGnXV4CYopwDsPg=
|
||||
|
||||
glob-base@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
|
||||
@@ -2613,6 +2669,13 @@ hosted-git-info@^2.1.4:
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
|
||||
integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
|
||||
|
||||
html-encoding-sniffer@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
|
||||
integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==
|
||||
dependencies:
|
||||
whatwg-encoding "^1.0.1"
|
||||
|
||||
html-inject-script@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/html-inject-script/-/html-inject-script-1.1.0.tgz#1a7c10a0fcbd309e85bf53d9a5ed24b74c5e3275"
|
||||
@@ -2693,7 +2756,7 @@ iconv-lite@0.4.23:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.4.4, iconv-lite@~0.4.13:
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
@@ -2818,6 +2881,11 @@ iota-array@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/iota-array/-/iota-array-1.0.0.tgz#81ef57fe5d05814cd58c2483632a99c30a0e8087"
|
||||
integrity sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc=
|
||||
|
||||
ip-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-3.0.0.tgz#0a934694b4066558c46294244a23cc33116bf732"
|
||||
integrity sha512-T8wDtjy+Qf2TAPDQmBp0eGKJ8GavlWlUnamr3wRn6vvdZlKVuJXXMlSncYFRYgVHOM3If5NR1H4+OvVQU9Idvg==
|
||||
|
||||
is-accessor-descriptor@^0.1.6:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
|
||||
@@ -3124,6 +3192,38 @@ jsbn@~0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
jsdom@^13.1.0:
|
||||
version "13.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-13.2.0.tgz#b1a0dbdadc255435262be8ea3723d2dba0d7eb3a"
|
||||
integrity sha512-cG1NtMWO9hWpqRNRR3dSvEQa8bFI6iLlqU2x4kwX51FQjp0qus8T9aBaAO6iGp3DeBrhdwuKxckknohkmfvsFw==
|
||||
dependencies:
|
||||
abab "^2.0.0"
|
||||
acorn "^6.0.4"
|
||||
acorn-globals "^4.3.0"
|
||||
array-equal "^1.0.0"
|
||||
cssom "^0.3.4"
|
||||
cssstyle "^1.1.1"
|
||||
data-urls "^1.1.0"
|
||||
domexception "^1.0.1"
|
||||
escodegen "^1.11.0"
|
||||
html-encoding-sniffer "^1.0.2"
|
||||
nwsapi "^2.0.9"
|
||||
parse5 "5.1.0"
|
||||
pn "^1.1.0"
|
||||
request "^2.88.0"
|
||||
request-promise-native "^1.0.5"
|
||||
saxes "^3.1.5"
|
||||
symbol-tree "^3.2.2"
|
||||
tough-cookie "^2.5.0"
|
||||
w3c-hr-time "^1.0.1"
|
||||
w3c-xmlserializer "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
whatwg-encoding "^1.0.5"
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^7.0.0"
|
||||
ws "^6.1.2"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
@@ -3185,10 +3285,10 @@ jsprim@^1.2.2:
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
jsqr@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-0.2.2.tgz#8c1f0279fb7c94542aaa9e8aeb7c722d523ea092"
|
||||
integrity sha1-jB8Ceft8lFQqqp6K63xyLVI+oJI=
|
||||
jsqr@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jsqr/-/jsqr-1.1.1.tgz#a0d7f95e6c3b0bec913dfef2ca64a877f28ed05f"
|
||||
integrity sha512-FVoMU2ncTyjaOqN/vwvDnZ7jaAVvFzM3LK3vG3jvQZFWJQlAwJ1XTCOgAEKo+4Rkd6ydMXTTvqGV/4w5VunmTw==
|
||||
|
||||
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
|
||||
version "3.2.2"
|
||||
@@ -3296,7 +3396,12 @@ lodash.memoize@~3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f"
|
||||
integrity sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=
|
||||
|
||||
lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10, lodash@~4.17.5:
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||
|
||||
lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10, lodash@~4.17.5:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
@@ -3313,10 +3418,10 @@ longest@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
|
||||
|
||||
looks-same@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/looks-same/-/looks-same-4.1.0.tgz#fa9593350dcddc79999fe130689860f9fb6afff2"
|
||||
integrity sha512-9dvYQrWpMhQzyyR25xRtFMq6TSXhduTcKKvYtlMf9IHzb+r/fvF+MQG6+hChC4MrLVlA+MRTOt6fhvUkbZ9IpA==
|
||||
looks-same@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/looks-same/-/looks-same-6.0.0.tgz#aa8f24291b78b966eb6fc315a41b33adeb3fc068"
|
||||
integrity sha512-143Xf0qKRubHjVlWiPI2VMOMbvS94ldHsYrccXvihe6nCI7Z/JFy5ZskQzpLtYy4TFX2vbSJM1uAn5gShvqlcw==
|
||||
dependencies:
|
||||
color-diff "^1.1.0"
|
||||
concat-stream "^1.6.2"
|
||||
@@ -3791,6 +3896,11 @@ number-is-nan@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
|
||||
|
||||
nwsapi@^2.0.9:
|
||||
version "2.0.9"
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.9.tgz#77ac0cdfdcad52b6a1151a84e73254edc33ed016"
|
||||
integrity sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
@@ -4055,6 +4165,11 @@ parse-passwd@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
|
||||
integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
|
||||
|
||||
parse5@5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
|
||||
integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==
|
||||
|
||||
parseqs@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
|
||||
@@ -4177,6 +4292,11 @@ plur@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156"
|
||||
integrity sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=
|
||||
|
||||
pn@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
|
||||
integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
|
||||
|
||||
pngjs-nozlib@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pngjs-nozlib/-/pngjs-nozlib-1.0.0.tgz#9e64d602cfe9cce4d9d5997d0687429a73f0b7d7"
|
||||
@@ -4255,6 +4375,11 @@ psl@^1.1.24:
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
|
||||
integrity sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==
|
||||
|
||||
psl@^1.1.28:
|
||||
version "1.1.31"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184"
|
||||
integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
|
||||
|
||||
public-encrypt@^4.0.0:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
|
||||
@@ -4277,6 +4402,11 @@ punycode@^1.3.2, punycode@^1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
qs@6.2.3:
|
||||
version "6.2.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe"
|
||||
@@ -4512,7 +4642,23 @@ repeating@^2.0.0:
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
request@^2.44.0, request@^2.45.0:
|
||||
request-promise-core@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6"
|
||||
integrity sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=
|
||||
dependencies:
|
||||
lodash "^4.13.1"
|
||||
|
||||
request-promise-native@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5"
|
||||
integrity sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=
|
||||
dependencies:
|
||||
request-promise-core "1.1.1"
|
||||
stealthy-require "^1.1.0"
|
||||
tough-cookie ">=2.3.3"
|
||||
|
||||
request@^2.44.0, request@^2.45.0, request@^2.88.0:
|
||||
version "2.88.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||
@@ -4692,6 +4838,13 @@ sax@^1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
saxes@^3.1.5:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.6.tgz#2d948a47b54918516c5a64096f08865deb5bd8cd"
|
||||
integrity sha512-LAYs+lChg1v5uKNzPtsgTxSS5hLo8aIhSMCJt1WMpefAxm3D1RTpMwSpb6ebdL31cubiLTnhokVktBW+cv9Y9w==
|
||||
dependencies:
|
||||
xmlchars "^1.3.1"
|
||||
|
||||
scope-analyzer@^2.0.1:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/scope-analyzer/-/scope-analyzer-2.0.5.tgz#72c9c6770c3e66984f84c7d3c7045998a1a7db8a"
|
||||
@@ -5118,6 +5271,11 @@ statuses@~1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||
integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
|
||||
|
||||
stealthy-require@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
||||
|
||||
stream-browserify@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db"
|
||||
@@ -5295,6 +5453,11 @@ symbol-observable@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
|
||||
integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=
|
||||
|
||||
symbol-tree@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
|
||||
integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=
|
||||
|
||||
syntax-error@^1.1.1:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c"
|
||||
@@ -5344,10 +5507,10 @@ tape-run@^5.0.0:
|
||||
through "~2.3.4"
|
||||
throughout "0.0.0"
|
||||
|
||||
tape@>=4.7.0:
|
||||
version "4.9.1"
|
||||
resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.1.tgz#1173d7337e040c76fbf42ec86fcabedc9b3805c9"
|
||||
integrity sha512-6fKIXknLpoe/Jp4rzHKFPpJUHDHDqn8jus99IfPnHIjyz78HYlefTGD3b5EkbQzuLfaEvmfPK3IolLgq2xT3kw==
|
||||
tape@^4.9.2:
|
||||
version "4.9.2"
|
||||
resolved "https://registry.yarnpkg.com/tape/-/tape-4.9.2.tgz#f233e40f09dc7e00fcf9b26755453c3822ad28c0"
|
||||
integrity sha512-lPXKRKILZ1kZaUy5ynWKs8ATGSUO7HAFHCFnBam6FaGSqPdOwMWbxXHq4EXFLE8WRTleo/YOMXkaUTRmTB1Fiw==
|
||||
dependencies:
|
||||
deep-equal "~1.0.1"
|
||||
defined "~1.0.0"
|
||||
@@ -5507,6 +5670,23 @@ to-regex@^3.0.1, to-regex@^3.0.2:
|
||||
regex-not "^1.0.2"
|
||||
safe-regex "^1.1.0"
|
||||
|
||||
tough-cookie@>=2.3.3:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.0.tgz#d2bceddebde633153ff20a52fa844a0dc71dacef"
|
||||
integrity sha512-LHMvg+RBP/mAVNqVbOX8t+iJ+tqhBA/t49DuI7+IDAWHrASnesqSu1vWbKB7UrE2yk+HMFUBMadRGMkB4VCfog==
|
||||
dependencies:
|
||||
ip-regex "^3.0.0"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
dependencies:
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
@@ -5515,6 +5695,13 @@ tough-cookie@~2.4.3:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
|
||||
tr46@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||
integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
trim-newlines@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
|
||||
@@ -5776,6 +5963,22 @@ vm-browserify@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
|
||||
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
|
||||
|
||||
w3c-hr-time@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
|
||||
integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=
|
||||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
|
||||
w3c-xmlserializer@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.0.1.tgz#054cdcd359dc5d1f3ec9be4e272c756af4b21d39"
|
||||
integrity sha512-XZGI1OH/OLQr/NaJhhPmzhngwcAnZDLytsvXnRmlYeRkmbb0I7sqFFA22erq4WQR0sUu17ZSQOAV9mFwCqKRNg==
|
||||
dependencies:
|
||||
domexception "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
watchify@^3.6.1:
|
||||
version "3.11.0"
|
||||
resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.11.0.tgz#03f1355c643955e7ab8dcbf399f624644221330f"
|
||||
@@ -5796,6 +5999,11 @@ wcwidth@^1.0.1:
|
||||
dependencies:
|
||||
defaults "^1.0.3"
|
||||
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
|
||||
|
||||
websocket-driver@>=0.5.1:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb"
|
||||
@@ -5809,6 +6017,27 @@ websocket-extensions@>=0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
|
||||
integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
|
||||
|
||||
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
||||
integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==
|
||||
dependencies:
|
||||
iconv-lite "0.4.24"
|
||||
|
||||
whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
|
||||
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
|
||||
|
||||
whatwg-url@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd"
|
||||
integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==
|
||||
dependencies:
|
||||
lodash.sortby "^4.7.0"
|
||||
tr46 "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
|
||||
which-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
|
||||
@@ -5866,6 +6095,13 @@ wrappy@1:
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
ws@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8"
|
||||
integrity sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
ws@~3.3.1:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"
|
||||
@@ -5883,6 +6119,16 @@ xhr-write-stream@^0.1.2:
|
||||
concat-stream "~0.1.0"
|
||||
ordered-emitter "~0.1.0"
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
|
||||
|
||||
xmlchars@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-1.3.1.tgz#1dda035f833dbb4f86a0c28eaa6ca769214793cf"
|
||||
integrity sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==
|
||||
|
||||
xmlhttprequest-ssl@~1.5.4:
|
||||
version "1.5.5"
|
||||
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
|
||||
|
||||
Reference in New Issue
Block a user