23 | */
24 | /*jslint bitwise: true, evil: true */
25 |
26 | /**
27 | * Adds methods to implement the HTML5 WindowTimers interface on a given
28 | * object.
29 | *
30 | * Adds the following methods:
31 | *
32 | * - clearInterval
33 | * - clearTimeout
34 | * - setInterval
35 | * - setTimeout
36 | *
37 | *
38 | * See http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html
39 | * for the complete specification of these methods.
40 | *
41 | * Example Usage
42 | * Browser compatibility in Rhino:
43 | * // Note: "this" refers to the global object in this example
44 | * var timerLoop = makeWindowTimer(this, java.lang.Thread.sleep);
45 | *
46 | * // Run code which may add intervals/timeouts
47 | *
48 | * timerLoop();
49 | *
50 | *
51 | * Browser compatibility in SpiderMonkey (smjs):
52 | * // Note: "this" refers to the global object in this example
53 | * var timerLoop = makeWindowTimer(this, function (ms) { sleep(ms / 1000); });
54 | *
55 | * // Run code which may add intervals/timeouts
56 | *
57 | * timerLoop();
58 | *
59 | *
60 | * For more esoteric uses, timerLoop will return instead of sleeping if passed
61 | * true which will run only events which are pending at the moment
62 | * timerLoop is called:
63 | * // Note: "this" refers to the global object in this example
64 | * var timerLoop = makeWindowTimer(this, java.lang.Thread.sleep);
65 | *
66 | * // Run code which may add intervals/timeouts
67 | *
68 | * while (timerLoop(true)) {
69 | * print("Still waiting...");
70 | * // Do other work here, possibly adding more intervals/timeouts
71 | * }
72 | *
73 | *
74 | * @param {Object} target Object to which the methods should be added.
75 | * @param {Function} sleep A function which sleeps for a specified number of
76 | * milliseconds.
77 | * @return {Function} The function which runs the scheduled timers.
78 | */
79 | function makeWindowTimer(target, sleep) {
80 | "use strict";
81 |
82 | var counter = 1,
83 | inCallback = false,
84 | // Map handle -> timer
85 | timersByHandle = {},
86 | // Min-heap of timers by time then handle, index 0 unused
87 | timersByTime = [ null ];
88 |
89 | /** Compares timers based on scheduled time and handle. */
90 | function timerCompare(t1, t2) {
91 | // Note: Only need less-than for our uses
92 | return t1.time < t2.time ? -1 :
93 | (t1.time === t2.time && t1.handle < t2.handle ? -1 : 0);
94 | }
95 |
96 | /** Fix the heap invariant which may be violated at a given index */
97 | function heapFixDown(heap, i, lesscmp) {
98 | var j, tmp;
99 |
100 | j = i * 2;
101 | while (j < heap.length) {
102 | if (j + 1 < heap.length &&
103 | lesscmp(heap[j + 1], heap[j]) < 0) {
104 | j = j + 1;
105 | }
106 |
107 | if (lesscmp(heap[i], heap[j]) < 0) {
108 | break;
109 | }
110 |
111 | tmp = heap[j];
112 | heap[j] = heap[i];
113 | heap[i] = tmp;
114 | i = j;
115 | j = i * 2;
116 | }
117 | }
118 |
119 | /** Fix the heap invariant which may be violated at a given index */
120 | function heapFixUp(heap, i, lesscmp) {
121 | var j, tmp;
122 | while (i > 1) {
123 | j = i >> 1; // Integer div by 2
124 |
125 | if (lesscmp(heap[j], heap[i]) < 0) {
126 | break;
127 | }
128 |
129 | tmp = heap[j];
130 | heap[j] = heap[i];
131 | heap[i] = tmp;
132 | i = j;
133 | }
134 | }
135 |
136 | /** Remove the minimum element from the heap */
137 | function heapPop(heap, lesscmp) {
138 | heap[1] = heap[heap.length - 1];
139 | heap.pop();
140 | heapFixDown(heap, 1, lesscmp);
141 | }
142 |
143 | /** Create a timer and schedule code to run at a given time */
144 | function addTimer(code, delay, repeat, argsIfFn) {
145 | var handle, timer;
146 |
147 | if (typeof code !== "function") {
148 | code = String(code);
149 | argsIfFn = null;
150 | }
151 | delay = Number(delay) || 0;
152 | if (inCallback) {
153 | delay = Math.max(delay, 4);
154 | }
155 | // Note: Must set handle after argument conversion to properly
156 | // handle conformance test in HTML5 spec.
157 | handle = counter;
158 | counter += 1;
159 |
160 | timer = {
161 | args: argsIfFn,
162 | cancel: false,
163 | code: code,
164 | handle: handle,
165 | repeat: repeat ? Math.max(delay, 4) : 0,
166 | time: new Date().getTime() + delay
167 | };
168 |
169 | timersByHandle[handle] = timer;
170 | timersByTime.push(timer);
171 | heapFixUp(timersByTime, timersByTime.length - 1, timerCompare);
172 |
173 | return handle;
174 | }
175 |
176 | /** Cancel an existing timer */
177 | function cancelTimer(handle, repeat) {
178 | var timer;
179 |
180 | if (timersByHandle.hasOwnProperty(handle)) {
181 | timer = timersByHandle[handle];
182 | if (repeat === (timer.repeat > 0)) {
183 | timer.cancel = true;
184 | }
185 | }
186 | }
187 |
188 | function clearInterval(handle) {
189 | cancelTimer(handle, true);
190 | }
191 | target.clearInterval = clearInterval;
192 |
193 | function clearTimeout(handle) {
194 | cancelTimer(handle, false);
195 | }
196 | target.clearTimeout = clearTimeout;
197 |
198 | function setInterval(code, delay) {
199 | return addTimer(
200 | code,
201 | delay,
202 | true,
203 | Array.prototype.slice.call(arguments, 2)
204 | );
205 | }
206 | target.setInterval = setInterval;
207 |
208 | function setTimeout(code, delay) {
209 | return addTimer(
210 | code,
211 | delay,
212 | false,
213 | Array.prototype.slice.call(arguments, 2)
214 | );
215 | }
216 | target.setTimeout = setTimeout;
217 |
218 | return function timerLoop(nonblocking) {
219 | var now, timer;
220 |
221 | // Note: index 0 unused in timersByTime
222 | while (timersByTime.length > 1) {
223 | timer = timersByTime[1];
224 |
225 | if (timer.cancel) {
226 | delete timersByHandle[timer.handle];
227 | heapPop(timersByTime, timerCompare);
228 | } else {
229 | now = new Date().getTime();
230 | if (timer.time <= now) {
231 | inCallback = true;
232 | try {
233 | if (typeof timer.code === "function") {
234 | timer.code.apply(undefined, timer.args);
235 | } else {
236 | eval(timer.code);
237 | }
238 | } finally {
239 | inCallback = false;
240 | }
241 |
242 | if (timer.repeat > 0 && !timer.cancel) {
243 | timer.time += timer.repeat;
244 | heapFixDown(timersByTime, 1, timerCompare);
245 | } else {
246 | delete timersByHandle[timer.handle];
247 | heapPop(timersByTime, timerCompare);
248 | }
249 | } else if (!nonblocking) {
250 | sleep(timer.time - now);
251 | } else {
252 | return true;
253 | }
254 | }
255 | }
256 |
257 | return false;
258 | };
259 | }
260 |
261 | if (typeof exports === "object") {
262 | exports.makeWindowTimer = makeWindowTimer;
263 | }
264 |
265 | // vi: set sts=4 sw=4 et :
--------------------------------------------------------------------------------
/app/src/main/java/com/jasonette/seed/Component/JasonTextareaComponent.java:
--------------------------------------------------------------------------------
1 | package com.jasonette.seed.Component;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.graphics.Typeface;
6 | import android.text.Editable;
7 | import android.text.InputType;
8 | import android.text.TextUtils;
9 | import android.text.TextWatcher;
10 | import android.util.Log;
11 | import android.view.Gravity;
12 | import android.view.KeyEvent;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.inputmethod.EditorInfo;
16 | import android.widget.EditText;
17 | import android.widget.TextView;
18 |
19 | import androidx.localbroadcastmanager.content.LocalBroadcastManager;
20 |
21 | import com.jasonette.seed.Core.JasonViewActivity;
22 | import com.jasonette.seed.Helper.JasonHelper;
23 |
24 | import org.json.JSONObject;
25 |
26 | public class JasonTextareaComponent {
27 | public static View build(View view, final JSONObject component, final JSONObject parent, final Context context) {
28 | if(view == null){
29 | return new EditText(context);
30 | } else {
31 | try {
32 | view = JasonComponent.build(view, component, parent, context);
33 |
34 | JSONObject style = JasonHelper.style(component, context);
35 | String type = component.getString("type");
36 |
37 | if (style.has("color")) {
38 | int color = JasonHelper.parse_color(style.getString("color"));
39 | ((TextView)view).setTextColor(color);
40 | }
41 | if (style.has("color:placeholder")) {
42 | int color = JasonHelper.parse_color(style.getString("color:placeholder"));
43 | ((TextView)view).setHintTextColor(color);
44 | }
45 |
46 | if (style.has("font:android")){
47 | String f = style.getString("font:android");
48 | if(f.equalsIgnoreCase("bold")){
49 | ((TextView) view).setTypeface(Typeface.DEFAULT_BOLD);
50 | } else if(f.equalsIgnoreCase("sans")){
51 | ((TextView) view).setTypeface(Typeface.SANS_SERIF);
52 | } else if(f.equalsIgnoreCase("serif")){
53 | ((TextView) view).setTypeface(Typeface.SERIF);
54 | } else if(f.equalsIgnoreCase("monospace")){
55 | ((TextView) view).setTypeface(Typeface.MONOSPACE);
56 | } else if(f.equalsIgnoreCase("default")){
57 | ((TextView) view).setTypeface(Typeface.DEFAULT);
58 | } else {
59 | try {
60 | Typeface font_type = Typeface.createFromAsset(context.getAssets(), "fonts/" + style.getString("font:android") + ".ttf");
61 | ((TextView) view).setTypeface(font_type);
62 | } catch (Exception e) {
63 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
64 | }
65 | }
66 | } else if (style.has("font")){
67 | if(style.getString("font").toLowerCase().contains("bold")) {
68 | if (style.getString("font").toLowerCase().contains("italic")) {
69 | ((TextView) view).setTypeface(Typeface.DEFAULT_BOLD, Typeface.ITALIC);
70 | } else {
71 | ((TextView) view).setTypeface(Typeface.DEFAULT_BOLD);
72 | }
73 | } else {
74 | if (style.getString("font").toLowerCase().contains("italic")) {
75 | ((TextView) view).setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
76 | } else {
77 | ((TextView) view).setTypeface(Typeface.DEFAULT);
78 | }
79 | }
80 | }
81 |
82 | if (!style.has("height")) {
83 | ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams)view.getLayoutParams();
84 | layoutParams.height = 300;
85 | view.setLayoutParams(layoutParams);
86 | }
87 |
88 | int g = 0;
89 | if (style.has("align")) {
90 | String align = style.getString("align");
91 | if (align.equalsIgnoreCase("center")) {
92 | g = g | Gravity.CENTER_HORIZONTAL;
93 | ((TextView) view).setGravity(Gravity.CENTER_HORIZONTAL);
94 | } else if (align.equalsIgnoreCase("right")) {
95 | g = g | Gravity.RIGHT;
96 | ((TextView) view).setGravity(Gravity.RIGHT);
97 | } else {
98 | g = g | Gravity.LEFT;
99 | }
100 |
101 | if (align.equalsIgnoreCase("bottom")) {
102 | g = g | Gravity.BOTTOM;
103 | } else {
104 | g = g | Gravity.TOP;
105 | }
106 | } else {
107 | g = Gravity.TOP | Gravity.LEFT;
108 | }
109 |
110 | ((EditText)view).setGravity(g);
111 |
112 | if (style.has("size")) {
113 | ((EditText)view).setTextSize(Float.parseFloat(style.getString("size")));
114 | }
115 |
116 |
117 | ((EditText)view).setEllipsize(TextUtils.TruncateAt.END);
118 |
119 |
120 | // placeholder
121 | if(component.has("placeholder")){
122 | ((EditText)view).setHint(component.getString("placeholder"));
123 | }
124 |
125 | // default value
126 | if(component.has("value")){
127 | ((EditText)view).setText(component.getString("value"));
128 | }
129 |
130 | // keyboard
131 | if(component.has("keyboard")){
132 | String keyboard = component.getString("keyboard");
133 | if(keyboard.equalsIgnoreCase("text")) {
134 | ((EditText) view).setInputType(InputType.TYPE_CLASS_TEXT);
135 | } else if(keyboard.equalsIgnoreCase("number")) {
136 | ((EditText) view).setInputType(InputType.TYPE_CLASS_NUMBER);
137 | } else if(keyboard.equalsIgnoreCase("decimal")) {
138 | ((EditText) view).setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_FLAG_DECIMAL);
139 | } else if(keyboard.equalsIgnoreCase("phone")) {
140 | ((EditText) view).setInputType(InputType.TYPE_CLASS_PHONE);
141 | } else if(keyboard.equalsIgnoreCase("url")) {
142 | ((EditText) view).setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
143 | } else if(keyboard.equalsIgnoreCase("email")) {
144 | ((EditText) view).setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
145 | }
146 | }
147 |
148 | // Data binding
149 | if(component.has("name")){
150 | ((EditText)view).addTextChangedListener(new TextWatcher() {
151 | @Override
152 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
153 |
154 | }
155 |
156 | @Override
157 | public void onTextChanged(CharSequence s, int start, int before, int count) {
158 |
159 | }
160 |
161 | @Override
162 | public void afterTextChanged(Editable s) {
163 | try {
164 | ((JasonViewActivity) context).model.var.put(component.getString("name"), s.toString());
165 | if(component.has("on")){
166 | JSONObject events = component.getJSONObject("on");
167 | if(events.has("change")){
168 | Intent intent = new Intent("call");
169 | intent.putExtra("action", events.getJSONObject("change").toString());
170 | LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
171 | }
172 | }
173 | } catch (Exception e){
174 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
175 | }
176 | }
177 | });
178 | }
179 | ((EditText)view).setOnEditorActionListener(new TextView.OnEditorActionListener() {
180 | @Override
181 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
182 | if (actionId == EditorInfo.IME_ACTION_DONE) {
183 | try {
184 | if(component.has("name")) {
185 | ((JasonViewActivity) context).model.var.put(component.getString("name"), v.getText().toString());
186 | }
187 | } catch (Exception e){
188 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
189 | }
190 | }
191 |
192 | return false;
193 | }
194 | });
195 |
196 | view.requestLayout();
197 | return view;
198 | } catch (Exception e){
199 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
200 | return new View(context);
201 | }
202 | }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/app/src/main/java/com/jasonette/seed/Component/JasonComponent.java:
--------------------------------------------------------------------------------
1 | package com.jasonette.seed.Component;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.GradientDrawable;
5 |
6 | import androidx.core.content.ContextCompat;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.LinearLayout;
10 | import android.widget.RelativeLayout;
11 |
12 | import com.jasonette.seed.Core.JasonViewActivity;
13 | import com.jasonette.seed.Helper.JasonHelper;
14 | import com.jasonette.seed.Section.JasonLayout;
15 |
16 | import org.json.JSONObject;
17 |
18 | public class JasonComponent {
19 |
20 | public static final String INTENT_ACTION_CALL = "call";
21 | public static final String ACTION_PROP = "action";
22 | public static final String DATA_PROP = "data";
23 | public static final String HREF_PROP = "href";
24 | public static final String TYPE_PROP = "type";
25 | public static final String OPTIONS_PROP = "options";
26 |
27 | public static View build(View view, final JSONObject component, final JSONObject parent, final Context root_context) {
28 | float width = 0;
29 | float height = 0;
30 | int corner_radius = 0;
31 |
32 | view.setTag(component);
33 | JSONObject style = JasonHelper.style(component, root_context);
34 |
35 | try{
36 | if(parent == null) {
37 | // Layer type
38 | width = RelativeLayout.LayoutParams.WRAP_CONTENT;
39 | height = RelativeLayout.LayoutParams.WRAP_CONTENT;
40 | if (style.has("height")) {
41 | try {
42 | height = (int) JasonHelper.pixels(root_context, style.getString("height"), "vertical");
43 | if (style.has("ratio")) {
44 | Float ratio = JasonHelper.ratio(style.getString("ratio"));
45 | width = height * ratio;
46 | }
47 | } catch (Exception e) {
48 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
49 | }
50 | }
51 | if (style.has("width")) {
52 | try {
53 | width = (int) JasonHelper.pixels(root_context, style.getString("width"), "horizontal");
54 | if (style.has("ratio")) {
55 | Float ratio = JasonHelper.ratio(style.getString("ratio"));
56 | height = width / ratio;
57 | }
58 | } catch (Exception e) {
59 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
60 | }
61 | }
62 |
63 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams((int)width, (int)height);
64 | view.setLayoutParams(layoutParams);
65 | } else {
66 | // Section item type
67 | LinearLayout.LayoutParams layoutParams = JasonLayout.autolayout(null, parent, component, root_context);
68 | view.setLayoutParams(layoutParams);
69 | }
70 |
71 | int bgcolor;
72 | if (style.has("background")) {
73 | int color = JasonHelper.parse_color(style.getString("background"));
74 | bgcolor = color;
75 | view.setBackgroundColor(color);
76 | } else {
77 | bgcolor = JasonHelper.parse_color("rgba(0,0,0,0)");
78 | }
79 | if(style.has("opacity"))
80 | {
81 | try {
82 | float opacity = (float) style.getDouble("opacity");
83 | view.setAlpha(opacity);
84 | }
85 | catch (Exception ex) {
86 | }
87 | }
88 |
89 |
90 | // padding
91 | int padding_left = (int)JasonHelper.pixels(root_context, "0", "horizontal");
92 | int padding_right = (int)JasonHelper.pixels(root_context, "0", "horizontal");
93 | int padding_top = (int)JasonHelper.pixels(root_context, "0", "horizontal");
94 | int padding_bottom = (int)JasonHelper.pixels(root_context, "0", "horizontal");
95 | if (style.has("padding")) {
96 | padding_left = (int)JasonHelper.pixels(root_context, style.getString("padding"), "horizontal");
97 | padding_right = padding_left;
98 | padding_top = padding_left;
99 | padding_bottom = padding_left;
100 | }
101 |
102 | // overwrite if more specific values exist
103 | if (style.has("padding_left")) {
104 | padding_left = (int)JasonHelper.pixels(root_context, style.getString("padding_left"), "horizontal");
105 | }
106 | if (style.has("padding_right")) {
107 | padding_right = (int)JasonHelper.pixels(root_context, style.getString("padding_right"), "horizontal");
108 | }
109 | if (style.has("padding_top")) {
110 | padding_top = (int)JasonHelper.pixels(root_context, style.getString("padding_top"), "vertical");
111 | }
112 | if (style.has("padding_bottom")) {
113 | padding_bottom = (int)JasonHelper.pixels(root_context, style.getString("padding_bottom"), "vertical");
114 | }
115 |
116 | if (style.has("corner_radius")) {
117 | float corner = JasonHelper.pixels(root_context, style.getString("corner_radius"), "horizontal");
118 | int color = ContextCompat.getColor(root_context, android.R.color.transparent);
119 | GradientDrawable cornerShape = new GradientDrawable();
120 | cornerShape.setShape(GradientDrawable.RECTANGLE);
121 | if (style.has("background")) {
122 | color = JasonHelper.parse_color(style.getString("background"));
123 | }
124 | cornerShape.setColor(color);
125 | cornerShape.setCornerRadius(corner);
126 |
127 | // border + corner_radius handling
128 | if (style.has("border_width")){
129 | int border_width = (int)JasonHelper.pixels(root_context, style.getString("border_width"), "horizontal");
130 | if(border_width > 0){
131 | int border_color;
132 | if (style.has("border_color")){
133 | border_color = JasonHelper.parse_color(style.getString("border_color"));
134 | } else {
135 | border_color = JasonHelper.parse_color("#000000");
136 | }
137 | cornerShape.setStroke(border_width, border_color);
138 | }
139 | }
140 | cornerShape.invalidateSelf();
141 | view.setBackground(cornerShape);
142 | } else {
143 | // border handling (no corner radius)
144 | if (style.has("border_width")){
145 | int border_width = (int)JasonHelper.pixels(root_context, style.getString("border_width"), "horizontal");
146 | if(border_width > 0){
147 | int border_color;
148 | if (style.has("border_color")){
149 | border_color = JasonHelper.parse_color(style.getString("border_color"));
150 | } else {
151 | border_color = JasonHelper.parse_color("#000000");
152 | }
153 | GradientDrawable cornerShape = new GradientDrawable();
154 | cornerShape.setStroke(border_width, border_color);
155 | cornerShape.setColor(bgcolor);
156 | cornerShape.invalidateSelf();
157 | view.setBackground(cornerShape);
158 | }
159 | }
160 |
161 | }
162 |
163 | view.setPadding(padding_left, padding_top, padding_right, padding_bottom);
164 | return view;
165 |
166 | } catch (Exception e){
167 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
168 | return new View(root_context);
169 | }
170 | }
171 | public static void addListener(final View view, final Context root_context){
172 | View.OnClickListener clickListener = new View.OnClickListener() {
173 | public void onClick(View v) {
174 | JSONObject component = (JSONObject)v.getTag();
175 | try {
176 | if (component.has("action")) {
177 | JSONObject action = component.getJSONObject("action");
178 | ((JasonViewActivity) root_context).call(action.toString(), new JSONObject().toString(), "{}", v.getContext());
179 | } else if (component.has("href")) {
180 | JSONObject href = component.getJSONObject("href");
181 | JSONObject action = new JSONObject().put("type", "$href").put("options", href);
182 | ((JasonViewActivity) root_context).call(action.toString(), new JSONObject().toString(), "{}", v.getContext());
183 | } else {
184 | // NONE Explicitly stated.
185 | // Need to bubble up all the way to the root viewholder.
186 | View cursor = view;
187 | while(cursor.getParent() != null) {
188 | JSONObject item = (JSONObject)(((View)cursor.getParent()).getTag());
189 | if (item!=null && (item.has("action") || item.has("href"))) {
190 | ((View)cursor.getParent()).performClick();
191 | break;
192 | } else {
193 | cursor = (View) cursor.getParent();
194 | }
195 | }
196 | }
197 | } catch (Exception e) {
198 | Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString());
199 | }
200 | }
201 | };
202 | view.setOnClickListener(clickListener);
203 | }
204 | }
205 |
--------------------------------------------------------------------------------