├── composer.json ├── examples ├── run.sh └── index.php ├── lib ├── DOM │ ├── SessionStorage.php │ ├── LocalStorage.php │ ├── PuenteStorage.php │ ├── Location.php │ ├── Console.php │ ├── Window.php │ └── ADomObject.php ├── Autoloader.php ├── Puente.php └── JQuery.php ├── LICENSE └── README.md /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jgmdev/puente", 3 | "description": "A proxy or bridge between PHP and jQuery.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Jefferson González", 8 | "email": "jgmdev@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=7.1" 13 | }, 14 | "autoload": { 15 | "psr-4": { 16 | "Puente\\": "lib/" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | runserver() { 4 | local port=8382 5 | local port_open=0 6 | 7 | until [ $port_open -eq 1 ]; do 8 | port=$(($port+1)) 9 | 10 | port_open=$(netstat -an | grep $port | grep LISTEN) 11 | 12 | if [ "$port_open" = "" ]; then 13 | port_open=1 14 | fi 15 | done 16 | 17 | php -S localhost:$port 18 | } 19 | 20 | echo "Open your web browser and point it to the url below." 21 | echo "====================================================" 22 | 23 | runserver 24 | -------------------------------------------------------------------------------- /lib/DOM/SessionStorage.php: -------------------------------------------------------------------------------- 1 | name = "sessionStorage"; 26 | $this->owner = $owner; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/Autoloader.php: -------------------------------------------------------------------------------- 1 | callMethod("setItem", $name, $value); 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Removes the specified local storage item. 43 | * 44 | * @param string $name 45 | * 46 | * @return \Puente\DOM\LocalStorage 47 | */ 48 | public function removeItem(string $name): self 49 | { 50 | $this->callMethod("removeItem", $name); 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Remove all local storage items. 57 | * 58 | * @return \Puente\DOM\LocalStorage 59 | */ 60 | public function clear(): self 61 | { 62 | $this->callMethod("clear"); 63 | 64 | return $this; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/index.php: -------------------------------------------------------------------------------- 1 | listenRequest() is called 9 | ob_start(); 10 | 11 | ?> 12 | 13 | 14 |
15 | 16 | jq("#message")->html("Hello World!")->click(function($puente, $data){ 20 | $system = `uname -a`; 21 | $puente->jq("#message")->html($system) 22 | ->css(["position" => "relative"]) 23 | ->animate(["top" => "+=20px"]) 24 | ; 25 | 26 | if($data["width"] > 500) 27 | { 28 | $puente->jq("#message")->toggle("slow", function($puente, $data){ 29 | if($data["visible"] == "false") 30 | { 31 | $puente->jq("#message")->toggle( 32 | "slow", 33 | function($puente, $data){ 34 | $puente->jq("#message")->html("keep it open!"); 35 | }, 36 | "{status: 'test'}" 37 | ); 38 | } 39 | else 40 | { 41 | $puente->jq("#message")->html(":)"); 42 | } 43 | }, "{visible: $('#message').is(':visible')}"); 44 | } 45 | }, "{width: $(window).width()}"); 46 | 47 | $puente->jq("#message")->css( 48 | ["border" => "solid 1px #000", "cursor" => "pointer"] 49 | ); 50 | 51 | $puente->jq("js:window")->resize(function($puente, $data){ 52 | $puente->window()->console()->log($data["width"]); 53 | }, "{width: $(window).width()}"); 54 | 55 | $puente->listenRequest(); 56 | 57 | $puente->executeCode(); 58 | -------------------------------------------------------------------------------- /lib/DOM/PuenteStorage.php: -------------------------------------------------------------------------------- 1 | instance = $owner->getInstanceID(); 26 | 27 | parent::__construct("Puente{$this->instance}", $owner); 28 | } 29 | 30 | /** 31 | * Inserts a variable to the Puente array storage. 32 | * 33 | * @param string $name 34 | * @param string $value 35 | * 36 | * @return \Puente\DOM\PuenteStorage 37 | */ 38 | public function insertVar(string $name): self 39 | { 40 | $this->owner->addCode( 41 | "Puente{$this->instance}['$name'] = $name;" 42 | ); 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * Removes a variable from the Puente array storage. 49 | * 50 | * @param string $name 51 | * @param string $value 52 | * 53 | * @return \Puente\DOM\PuenteStorage 54 | */ 55 | public function removeVar(string $name): self 56 | { 57 | $this->owner->addCode( 58 | "delete Puente{$this->instance}['$name'];" 59 | ); 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Gets the Puente instance with the variable name as index which 66 | * is useful in different scenarios, lets say you stored a setInterval 67 | * object and want to clear it out with clearInterval, eg: 68 | * clearInvertal($storage->getVarName("myInterval")) 69 | * would translate to: 70 | * clearInterval(Puente1['myInterval']) 71 | * 72 | * @param string $name 73 | * 74 | * @return string 75 | */ 76 | public function getVarInstance(string $name): string 77 | { 78 | return "Puente{$this->instance}['$name']"; 79 | } 80 | 81 | /** 82 | * Remove all variables. 83 | * 84 | * @return \Puente\DOM\PuenteStorage 85 | */ 86 | public function clear(): self 87 | { 88 | $this->owner->addCode( 89 | "Puente{$this->instance} = [];" 90 | ); 91 | 92 | return $this; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/DOM/Location.php: -------------------------------------------------------------------------------- 1 | callMethod("assign", $url); 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * Reloads the current document. 44 | * 45 | * @param bool $force_get If false (default) reloads from browser cache, 46 | * if true downloads a fresh copy. 47 | * 48 | * @return \Puente\DOM\Location 49 | */ 50 | public function reload(bool $force_get=false): self 51 | { 52 | $this->callMethod("reload", $force_get ? "js:true" : "js:false"); 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * Replaces the current document with a new one. It removes current document 59 | * from browser history so it is not possible to navigate back to it from 60 | * the user browser. 61 | * 62 | * @param string $url 63 | * 64 | * @return \Puente\DOM\Location 65 | */ 66 | public function replace(string $url): self 67 | { 68 | $this->callMethod("replace", $url); 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Set the anchor part of the current url (#anchor). 75 | * 76 | * @param string $value 77 | * 78 | * @return \Puente\DOM\Location 79 | */ 80 | public function hash(string $value): self 81 | { 82 | $this->assignProperty("hash", $value); 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * Set the hostname and port, eg: myhost:8080. 89 | * 90 | * @param string $value 91 | * 92 | * @return \Puente\DOM\Location 93 | */ 94 | public function host(string $value): self 95 | { 96 | $this->assignProperty("host", $value); 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Set the hostname, eg: myhost.com. 103 | * 104 | * @param string $value 105 | * 106 | * @return \Puente\DOM\Location 107 | */ 108 | public function hostname(string $value): self 109 | { 110 | $this->assignProperty("hostname", $value); 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Set the entire url, eg: http://mysite.com/something?stuff=stuff. 117 | * 118 | * @param string $value 119 | * 120 | * @return \Puente\DOM\Location 121 | */ 122 | public function href(string $value): self 123 | { 124 | $this->assignProperty("href", $value); 125 | 126 | return $this; 127 | } 128 | 129 | /** 130 | * Set the path part of current url. 131 | * 132 | * @param string $value 133 | * 134 | * @return \Puente\DOM\Location 135 | */ 136 | public function pathname(string $value): self 137 | { 138 | $this->assignProperty("pathname", $value); 139 | 140 | return $this; 141 | } 142 | 143 | /** 144 | * Set the port of current url. 145 | * 146 | * @param string $value 147 | * 148 | * @return \Puente\DOM\Location 149 | */ 150 | public function port(string $value): self 151 | { 152 | $this->assignProperty("port", $value); 153 | 154 | return $this; 155 | } 156 | 157 | /** 158 | * Set the protocol part of the url. Posible values can be: 159 | * file:, ftp:, http:, https: and mailto: 160 | * 161 | * @param string $value 162 | * 163 | * @return \Puente\DOM\Location 164 | */ 165 | public function protocol(string $value): self 166 | { 167 | $this->assignProperty("protocol", $value); 168 | 169 | return $this; 170 | } 171 | 172 | /** 173 | * Set the query string part of the url, eg: ?myvar=value 174 | * 175 | * @param string $value 176 | * 177 | * @return \Puente\DOM\Location 178 | */ 179 | public function search(string $value): self 180 | { 181 | $this->assignProperty("search", $value); 182 | 183 | return $this; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Puente :bridge_at_night: 2 | 3 | **Puente** which is the spanish word for "*bridge*" (you can hear the 4 | pronunciation [here](https://www.howtopronounce.com/spanish/puente/)), is a 5 | PHP library that facilitates the communication between your php code and 6 | jQuery/JavaScript code. It serves as a jQuery wrapper that generates working 7 | JavaScript code. It uses ajax functionality to send all registered browser 8 | events back to php for server side processing, then it returns more JavaScript 9 | code to the client browser. 10 | 11 | ## Why? 12 | 13 | Today's web development process can be tedious. You can achieve the same goal 14 | in 1000 different ways, many JavaScript libraries exist that facilitate the 15 | communication between your frontend and backend. Examples of these libraries 16 | are: 17 | 18 | * Angular 19 | * Aurelia 20 | * Backbone.js 21 | * Ember.js 22 | * Meteor 23 | * Mithril 24 | * React 25 | * Vue.js 26 | * Polymer 27 | * (insert more frameworks here... :trollface:) 28 | 29 | Many stuff exists and keeps proliferating, making a web developer life harder. 30 | Knowledge doesn't comes for free and you will have to invest time learning these 31 | JavaScript frameworks. While this is yet another project that helps you achieve 32 | the same goal, it is based on the solid jQuery library that has been around for 33 | many years now. jQuery is easy to learn and almost every web developer has 34 | worked with it. 35 | 36 | What this project does is ease the communication between the user browser 37 | and your backend. This project is not intended to remove the need of writing 38 | JavaScript code, but to make it easier to interact with the frontend from the 39 | backend without needing to implement a Web API for every basic stuff you have 40 | to do. 41 | 42 | For a better idea of what this project has to offer keep reading below. 43 | 44 | ## Usage 45 | 46 | First you will need to include the jQuery library in your html code: 47 | 48 | ```html 49 | 50 | ``` 51 | 52 | Then you will have to initialize a Puente instance: 53 | 54 | ```php 55 | $puente = new \Puente\Puente(); 56 | ``` 57 | 58 | To manipulate a DOM element you will use the **jq()** method which will return 59 | a JQuery object instance that mimics the jQuery functionality: 60 | 61 | ```php 62 | $puente->jq("#message")->html("Hello World!"); 63 | ``` 64 | 65 | You can register events as you would do with jQuery, with the **difference** that 66 | you will be able to register a **PHP callback!**: 67 | 68 | ```php 69 | $puente->jq(".element")->click(function($puente, $data){ 70 | $puente->jq("js:this")->text("Hello World!"); 71 | }); 72 | ``` 73 | 74 | You can access other DOM objects like **window**, **console**, **location**, 75 | **localStorage** and **sessionStorage**, the possibilities for more are 76 | endless: 77 | 78 | ```php 79 | $puente->jq(".element")->click(function($puente, $data){ 80 | $puente->window()->alert("Hello World!"); 81 | }); 82 | ``` 83 | 84 | Also, when calling JavaScript functions you may want to give it a JavaScript 85 | object instead of a string, which you can achieve by using the **js:** prefix: 86 | 87 | ```php 88 | $puente->jq(".element")->click(function($puente, $data){ 89 | // This will actually show the value of window.innerWidth instead 90 | // of literally showing the string. 91 | $puente->window()->alert("js:window.innerWidth"); 92 | }); 93 | ``` 94 | 95 | When registering an event you can tell it to fetch data from user browser by 96 | giving a valid JSON string to the **$data** parameter: 97 | 98 | ```php 99 | $puente->jq(".element")->click( 100 | function($puente, $data){ 101 | $puente->window()->alert($data["width"]); 102 | }, 103 | "{width: window.innerWidth}" //You can also feed it php arrays and objects. 104 | ); 105 | ``` 106 | 107 | This will send the client browser window width back to the php callback. 108 | 109 | ### Listening the registered events 110 | 111 | All events like click, dblclick, etc... will now need to be listened by your 112 | php script, for this all you need to do is call the following method: 113 | 114 | ```php 115 | $puente->listenRequest(); 116 | ``` 117 | 118 | This will be in charge of checking if a request to the same page that holds 119 | the Puente code comes from the user browser and respond to it. 120 | 121 | ### Generating the code 122 | 123 | After writing your Puente logic you will have to tell it to generate the 124 | JavaScript code: 125 | 126 | ```php 127 | $puente->executeCode(); //This actually prints the generated code to the document 128 | ``` 129 | 130 | If you dont want to directly print the code you can call 131 | **getExecuteCode()** instead: 132 | 133 | ```php 134 | $code = $puente->getExecuteCode(); //Now you can decide what to do with it 135 | ``` 136 | 137 | ## Examples 138 | 139 | To test the examples you will need PHP CLI to be installed and available on 140 | your system path, then open a terminal and inside the **puente** project folder 141 | do the following: 142 | 143 | ```sh 144 | cd examples 145 | ./run.sh 146 | ``` 147 | 148 | After running the **run.sh** script open your web browser and point 149 | it to the returned address on your terminal which by default is: 150 | 151 | > http://localhost:8383 152 | 153 | ## Showcase 154 | 155 | [BlueControl](https://github.com/jgmdev/bluecontrol) - php application that 156 | controls blue light on display and uses Puente to handle the configuration 157 | GUI dynamic events. 158 | 159 | ## Status 160 | 161 | The library is still **under development** but it is already proving to be 162 | useful. Many stuff could still be added. 163 | 164 | ## TODO 165 | 166 | Add more examples and use the index.php file as the main starting 167 | point that list all the available examples. 168 | -------------------------------------------------------------------------------- /lib/DOM/Console.php: -------------------------------------------------------------------------------- 1 | "john", age => 10], ["name" => "Smith", age => 4]]. 34 | * @param string $message The message to display with the element. 35 | * 36 | * @return \Puente\DOM\Console 37 | */ 38 | public function assert( 39 | $element, string $message="" 40 | ): self 41 | { 42 | if(is_string($element)) 43 | { 44 | $element = "js:$element"; 45 | } 46 | 47 | if($message) 48 | { 49 | $this->callMethod("assert", $element, $message); 50 | } 51 | else 52 | { 53 | $this->callMethod("assert", $element); 54 | } 55 | 56 | return $this; 57 | } 58 | 59 | /** 60 | * Writes an error message to the console. 61 | * 62 | * @param string $message The message to write. 63 | * 64 | * @return \Puente\DOM\Console 65 | */ 66 | public function error(string $message): self 67 | { 68 | $this->callMethod("error", $message); 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Writes a message to the console 75 | * 76 | * @param string $message The message or object to write. 77 | * 78 | * @return \Puente\DOM\Console 79 | */ 80 | public function info(string $message): self 81 | { 82 | $this->callMethod("info", $message); 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * Writes a message to the console 89 | * 90 | * @param string $message The message or object to write. 91 | * 92 | * @return \Puente\DOM\Console 93 | */ 94 | public function log(string $message): self 95 | { 96 | $this->callMethod("log", $message); 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Writes a warning message to the console. 103 | * 104 | * @param string $message The message or object to write. 105 | * 106 | * @return \Puente\DOM\Console 107 | */ 108 | public function warn(string $message): self 109 | { 110 | $this->callMethod("warn", $message); 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Clears the debugging console. and writes a message in the console: 117 | * "Console was cleared". 118 | * 119 | * @return \Puente\DOM\Console 120 | */ 121 | public function clear(): self 122 | { 123 | $this->callMethod("clear"); 124 | 125 | return $this; 126 | } 127 | 128 | /** 129 | * Writes to the console the number of times that particular console.count() 130 | * is called. You can add a label that will be included in the console view. 131 | * 132 | * @param string $label If set the method counts the number of times 133 | * console.count() has been called with this label. 134 | * 135 | * @return \Puente\DOM\Console 136 | */ 137 | public function count(string $label=""): self 138 | { 139 | if($label) 140 | { 141 | $this->callMethod("count", $label); 142 | } 143 | else 144 | { 145 | $this->callMethod("count"); 146 | } 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * Indicates the start of a message group. All messages will from now on 153 | * be written inside this group. 154 | * 155 | * @param string $label If set the messages are grouped by the given label. 156 | * 157 | * @return \Puente\DOM\Console 158 | */ 159 | public function group(string $label=""): self 160 | { 161 | if($label) 162 | { 163 | $this->callMethod("group", $label); 164 | } 165 | else 166 | { 167 | $this->callMethod("group"); 168 | } 169 | 170 | return $this; 171 | } 172 | 173 | /** 174 | * Same as group but the user will need to uncollapse messages to read them. 175 | * 176 | * @param string $label If set the messages are grouped by the given label. 177 | * 178 | * @return \Puente\DOM\Console 179 | */ 180 | public function groupCollapsed(string $label=""): self 181 | { 182 | if($label) 183 | { 184 | $this->callMethod("groupCollapsed", $label); 185 | } 186 | else 187 | { 188 | $this->callMethod("groupCollapsed"); 189 | } 190 | 191 | return $this; 192 | } 193 | 194 | /** 195 | * Ends a previously started messages group. 196 | * 197 | * @return \Puente\DOM\Console 198 | */ 199 | public function groupEnd(): self 200 | { 201 | $this->callMethod("groupEnd"); 202 | 203 | return $this; 204 | } 205 | 206 | /** 207 | * Writes a table to the console 208 | * 209 | * @param string|array $element A string representing a javascript object 210 | * or php array of associative elements, for example: 211 | * [["name" => "john", age => 10], ["name" => "Smith", age => 4]]. 212 | * @param array $columnNames Array of the columns to display, for example: 213 | * ["age"] which will display only the age column. 214 | * 215 | * @return \Puente\DOM\Console 216 | */ 217 | public function table( 218 | $element, array $columnNames=[] 219 | ): self 220 | { 221 | if(is_string($element)) 222 | { 223 | $element = "js:$element"; 224 | } 225 | 226 | if(count($columnNames) > 0) 227 | { 228 | $this->callMethod("table", $element, $columnNames); 229 | } 230 | else 231 | { 232 | $this->callMethod("table", $element); 233 | } 234 | 235 | return $this; 236 | } 237 | 238 | /** 239 | * Starts a timer that counts the amount of time since started. 240 | * 241 | * @param string $label If set the timer is identified as label. 242 | * 243 | * @return \Puente\DOM\Console 244 | */ 245 | public function time(string $label=""): self 246 | { 247 | if($label) 248 | { 249 | $this->callMethod("time", $label); 250 | } 251 | else 252 | { 253 | $this->callMethod("time"); 254 | } 255 | 256 | return $this; 257 | } 258 | 259 | /** 260 | * Ends a timer and write the total amount of time on the console. 261 | * 262 | * @param string $label If set the timer is identified as label. 263 | * 264 | * @return \Puente\DOM\Console 265 | */ 266 | public function timeEnd(string $label=""): self 267 | { 268 | if($label) 269 | { 270 | $this->callMethod("timeEnd", $label); 271 | } 272 | else 273 | { 274 | $this->callMethod("timeEnd"); 275 | } 276 | 277 | return $this; 278 | } 279 | 280 | /** 281 | * Displays a trace that show how the code ended before calling. 282 | * 283 | * @param string $label If set the trace is identified as the given label. 284 | * 285 | * @return \Puente\DOM\Console 286 | */ 287 | public function trace(string $label=""): self 288 | { 289 | if($label) 290 | { 291 | $this->callMethod("trace", $label); 292 | } 293 | else 294 | { 295 | $this->callMethod("trace"); 296 | } 297 | 298 | return $this; 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /lib/DOM/Window.php: -------------------------------------------------------------------------------- 1 | console = new Console($owner); 39 | 40 | $this->location = new Location($owner); 41 | } 42 | 43 | /** 44 | * Gives you access to the browser console which provides methods 45 | * for logging information to the browser's console 46 | * 47 | * @return \Puente\DOM\Console 48 | */ 49 | public function console(): Console 50 | { 51 | return $this->console; 52 | } 53 | 54 | /** 55 | * Gives you access to the location object. 56 | * 57 | * @return \Puente\DOM\Location 58 | */ 59 | public function location(): Location 60 | { 61 | return $this->location; 62 | } 63 | 64 | /** 65 | * Display an alert dialog box. 66 | * 67 | * @param string $message 68 | * 69 | * @return \Puente\DOM\Window 70 | */ 71 | public function alert(string $message): self 72 | { 73 | $this->callMethod("alert", $message); 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * Generates a confirm dialog, and calls the given server side callback. 80 | * 81 | * @param string $message 82 | * @param callable $callback function(Puente\Puente, array{"confirm" => bool}) 83 | * 84 | * @return \Puente\DOM\Window 85 | */ 86 | public function confirm(string $message, callable $callback): self 87 | { 88 | $this->paramConvert($message); 89 | 90 | $this->owner->addCode("var output = confirm($message);"); 91 | 92 | $this->owner->addEvent($callback, '{"confirm": output}'); 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Opens a prompt dialog to ask user for input. 99 | * 100 | * @param string $message 101 | * @param callable $callback function(Puente\Puente, array{"input" => string}) 102 | * @param string $default_value The default value of the prompt displayed 103 | * to the user. 104 | * 105 | * @return \Puente\DOM\Window 106 | */ 107 | public function prompt( 108 | string $message, callable $callback, string $default_value="" 109 | ): self 110 | { 111 | $this->paramConvert($message); 112 | $this->paramConvert($default_value); 113 | 114 | $this->owner->addCode( 115 | "var input = prompt($message, $default_value);" 116 | ); 117 | 118 | $this->owner->addEvent($callback, '{"input": input}'); 119 | 120 | return $this; 121 | } 122 | 123 | /** 124 | * Opens a new browser window or tab depending on the user browser settings. 125 | * Stores the window object in the puente storage for later manipulation. 126 | * 127 | * @param string $url The url to open, a blank value will open a new tab. 128 | * @param string $target Can be _blank, _parent, _self or _top. 129 | * @param string $varname An explicit name for the variable that will store 130 | * the new opened window. 131 | * 132 | * @return \Puente\DOM\Window Reference to newly created window. 133 | */ 134 | public function open( 135 | string $url, string $target="_blank", string $varname="" 136 | ): self 137 | { 138 | $this->paramConvert($url); 139 | $this->paramConvert($target); 140 | 141 | $varname = $varname == "" ? uniqid("win") : $varname; 142 | 143 | $this->owner->addCode( 144 | $varname."=".$this->name.".open($url, $target);" 145 | ); 146 | 147 | $this->owner->puenteStorage()->insertVar($varname); 148 | 149 | $new_window = new self($this->owner, $varname); 150 | 151 | return $new_window; 152 | } 153 | 154 | /** 155 | * Closes the current window. 156 | * 157 | * @return \Puente\DOM\Window 158 | */ 159 | public function close(): self 160 | { 161 | $this->callMethod("close"); 162 | return $this; 163 | } 164 | 165 | /** 166 | * Opens the Print Dialog Box, which lets the user select preferred 167 | * printing options to print the content of the current window. 168 | * 169 | * @return \Puente\DOM\Window 170 | */ 171 | public function print(): self 172 | { 173 | $this->callMethod("print"); 174 | return $this; 175 | } 176 | 177 | /** 178 | * Remove focus from the current window. 179 | * 180 | * @return \Puente\DOM\Window 181 | */ 182 | public function blur(): self 183 | { 184 | $this->callMethod("print"); 185 | return $this; 186 | } 187 | 188 | /** 189 | * Sets focus to the current window. 190 | * 191 | * @return \Puente\DOM\Window 192 | */ 193 | public function focus(): self 194 | { 195 | $this->callMethod("print"); 196 | return $this; 197 | } 198 | 199 | /** 200 | * Calls a function after a specified number of milliseconds. This function 201 | * will add a 'timeout' element to the $data object sent to the callback 202 | * that contains the variable name which holds the timer id. 203 | * 204 | * @param callable $callback 205 | * @param int $milliseconds 206 | * @param string $varname An explicit name for the variable that will store 207 | * the timer id, if empty it will generate one for you. 208 | * @param string|array|object $data The data you want on your callback 209 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 210 | * 211 | * @return \Puente\DOM\Window 212 | */ 213 | public function setTimeout( 214 | callable $callback, int $milliseconds=0, string $varname="", $data="{}" 215 | ): self 216 | { 217 | $varname = $varname == "" ? uniqid("timeout") : $varname; 218 | 219 | $this->appendData($data, ["timeout" => $varname]); 220 | 221 | $this->owner->addEventCallback( 222 | "var $varname = {$this->name}.setTimeout(" 223 | . "{callback}, $milliseconds" 224 | . ");", 225 | $callback, 226 | $data 227 | ); 228 | 229 | $this->owner->puenteStorage()->insertVar($varname); 230 | 231 | return $this; 232 | } 233 | 234 | /** 235 | * Calls a function at specified intervals in milliseconds. This function 236 | * will add an 'interval' element to the $data object sent to the callback 237 | * that contains the variable name whichs holds timer id, this way 238 | * you can use clearInterval from within the callback in case you want 239 | * to stop the interval. 240 | * 241 | * @param callable $callback 242 | * @param int $milliseconds 243 | * @param string $varname An explicit name for the variable that will store 244 | * the timer id, if empty it will generate one for you. 245 | * @param string|array|object $data The data you want on your callback 246 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 247 | * 248 | * @return \Puente\DOM\Window 249 | */ 250 | public function setInterval( 251 | callable $callback, int $milliseconds=0, string $varname="", $data="{}" 252 | ): self 253 | { 254 | $varname = $varname == "" ? uniqid("interval") : $varname; 255 | 256 | $this->appendData($data, ["interval" => $varname]); 257 | 258 | $this->owner->addEventCallback( 259 | "var $varname = {$this->name}.setInterval(" 260 | . "{callback}, $milliseconds" 261 | . ");", 262 | $callback, 263 | $data 264 | ); 265 | 266 | $this->owner->puenteStorage()->insertVar($varname); 267 | 268 | return $this; 269 | } 270 | 271 | /** 272 | * Stops a timer started with setTimeout(). 273 | * 274 | * @param string $varname 275 | * 276 | * @return \Puente\DOM\Window 277 | */ 278 | public function clearTimeout(string $varname): self 279 | { 280 | $this->owner->addCode( 281 | "clearTimeout(" 282 | . $this->owner->puenteStorage()->getVarInstance($varname) 283 | . ");" 284 | ); 285 | 286 | $this->owner->puenteStorage()->removeVar($varname); 287 | 288 | return $this; 289 | } 290 | 291 | /** 292 | * Stops a timer started with setInterval(). 293 | * 294 | * @param string $varname 295 | * 296 | * @return \Puente\DOM\Window 297 | */ 298 | public function clearInterval(string $varname): self 299 | { 300 | $this->owner->addCode( 301 | "clearInterval(" 302 | . $this->owner->puenteStorage()->getVarInstance($varname) 303 | . ");" 304 | ); 305 | 306 | $this->owner->puenteStorage()->removeVar($varname); 307 | 308 | return $this; 309 | } 310 | 311 | /** 312 | * Resizes a window to the specified width and height. 313 | * 314 | * @param integer $width 315 | * @param integer $height 316 | * 317 | * @return \Puente\DOM\Window 318 | */ 319 | public function resizeTo(int $width, int $height): self 320 | { 321 | $this->callMethod("resizeTo", $width, $height); 322 | 323 | return $this; 324 | } 325 | 326 | /** 327 | * Moves a window's left and top edge to the specified coordinates. 328 | * 329 | * @param integer $width 330 | * @param integer $height 331 | * 332 | * @return \Puente\DOM\Window 333 | */ 334 | public function moveTo(int $width, int $height): self 335 | { 336 | $this->callMethod("moveTo", $width, $height); 337 | 338 | return $this; 339 | } 340 | } -------------------------------------------------------------------------------- /lib/DOM/ADomObject.php: -------------------------------------------------------------------------------- 1 | name = $name; 42 | $this->owner = $owner; 43 | $this->code = ""; 44 | $this->identifier = ""; 45 | } 46 | 47 | /** 48 | * Magic method that generates the code for non implemented methods. 49 | * 50 | * @param string $name 51 | * @param array $arguments 52 | * 53 | * @return self 54 | */ 55 | public function __call(string $name, array $arguments): self 56 | { 57 | if(!$this->name) 58 | { 59 | throw new \Exception("No name specified for the DOM object."); 60 | } 61 | 62 | switch(count($arguments)) 63 | { 64 | case 0: 65 | $this->callMethod($name); 66 | break; 67 | case 1: 68 | $this->callMethod($name, $arguments[0]); 69 | break; 70 | case 2: 71 | $this->callMethod($name, $arguments[0], $arguments[1]); 72 | break; 73 | case 3: 74 | $this->callMethod( 75 | $name, $arguments[0], $arguments[1], $arguments[2] 76 | ); 77 | break; 78 | case 4: 79 | $this->callMethod( 80 | $name, $arguments[0], $arguments[1], 81 | $arguments[2], $arguments[3] 82 | ); 83 | break; 84 | case 5: 85 | $this->callMethod( 86 | $name, $arguments[0], $arguments[1], 87 | $arguments[2], $arguments[3], $arguments[4] 88 | ); 89 | break; 90 | default: 91 | throw new \Exception("Too many arguments."); 92 | } 93 | 94 | return $this; 95 | } 96 | 97 | /** 98 | * Generates code to call DOM object method. 99 | * 100 | * @param string $name 101 | * @param array ...$arguments 102 | * 103 | * @return self 104 | */ 105 | public function callMethod(string $name, ...$arguments): self 106 | { 107 | if(!$this->name) 108 | { 109 | throw new \Exception("No name specified for the DOM object."); 110 | } 111 | 112 | $args = ""; 113 | if(count($arguments) > 0) 114 | { 115 | foreach($arguments as $value) 116 | { 117 | $this->paramConvert($value); 118 | 119 | $args .= $value . ", "; 120 | } 121 | 122 | $args = rtrim($args, ", "); 123 | } 124 | 125 | if($this->owner) 126 | { 127 | if(!$this->identifier) 128 | { 129 | $this->owner->addCode( 130 | "{$this->name}.$name(" 131 | . $args 132 | . ");" 133 | ); 134 | } 135 | else 136 | { 137 | $current_code = rtrim( 138 | $this->owner->getCode($this->identifier), 139 | ";" 140 | ); 141 | 142 | if($current_code) 143 | { 144 | $current_code .= ".$name(" 145 | . $args 146 | . ");" 147 | ; 148 | } 149 | else 150 | { 151 | $current_code .= "{$this->name}.$name(" 152 | . $args 153 | . ");" 154 | ; 155 | } 156 | 157 | $this->owner->addCode($current_code, $this->identifier); 158 | } 159 | } 160 | else 161 | { 162 | if($this->code) 163 | { 164 | $this->code .= ".$name(" 165 | . $args 166 | . ")" 167 | ; 168 | } 169 | else 170 | { 171 | $this->code .= "{$this->name}.$name(" 172 | . $args 173 | . ")" 174 | ; 175 | } 176 | } 177 | 178 | return $this; 179 | } 180 | 181 | /** 182 | * Generates code that sets a DOM object property. 183 | * 184 | * @param string $name 185 | * @param string|array|object $value 186 | * 187 | * @return self 188 | */ 189 | public function assignProperty(string $name, $value): self 190 | { 191 | if(!$this->name) 192 | { 193 | throw new \Exception("No name specified for the DOM object."); 194 | } 195 | 196 | $this->paramConvert($value); 197 | 198 | if($this->owner) 199 | { 200 | $this->owner->addCode("{$this->name}.$name=$value;"); 201 | } 202 | else 203 | { 204 | if($this->code) 205 | { 206 | $this->code .= "; {$this->name}.$name=$value"; 207 | } 208 | else 209 | { 210 | $this->code .= "{$this->name}.$name=$value"; 211 | } 212 | } 213 | 214 | return $this; 215 | } 216 | 217 | /** 218 | * Get generated code if object doesn't have an owner. 219 | * 220 | * @return string 221 | */ 222 | public function getCode(): string 223 | { 224 | return "js:".$this->code; 225 | } 226 | 227 | /** 228 | * Get generated code if object doesn't have an owner including the ; at 229 | * the end. 230 | * 231 | * @return string 232 | */ 233 | public function getCodeEnded(): string 234 | { 235 | return "js:".$this->code . ";"; 236 | } 237 | 238 | /** 239 | * Appends data fields to a data object that will be sent to a callback. 240 | * 241 | * @param string|array|object $data 242 | * @param array $new_data 243 | * 244 | * @return self 245 | */ 246 | public function appendData(&$data, array $new_data): self 247 | { 248 | if(count($new_data) <= 0) 249 | { 250 | return $this; 251 | } 252 | 253 | if(is_string($data)) 254 | { 255 | $data = trim($data); 256 | 257 | if(substr($data, -1) == "}") 258 | { 259 | $data = substr_replace($data, "", -1); 260 | 261 | foreach($new_data as $name => $value) 262 | { 263 | $this->paramConvert($value); 264 | $data .= ", $name: $value"; 265 | } 266 | 267 | if(substr($data, 0, 2) == "{,") 268 | { 269 | $data = substr_replace($data, "{", 0, 2); 270 | } 271 | 272 | $data .= "}"; 273 | } 274 | else 275 | { 276 | throw new \Exception("Invalid JSON Object."); 277 | } 278 | } 279 | elseif(is_array($data)) 280 | { 281 | foreach($new_data as $name => $value) 282 | { 283 | $this->paramConvert($value); 284 | $data[$name] = $value; 285 | } 286 | } 287 | elseif(is_object($data)) 288 | { 289 | foreach($new_data as $name => $value) 290 | { 291 | $this->paramConvert($value); 292 | $data->$name = $value; 293 | } 294 | } 295 | 296 | return $this; 297 | } 298 | 299 | /** 300 | * Returns the name of the element we are working on, this can be 301 | * an object or variable name. 302 | * 303 | * @return string 304 | */ 305 | public function getName(): string 306 | { 307 | return $this->name; 308 | } 309 | 310 | /** 311 | * Converts the paremeter to a valid string or object that can be feed 312 | * into a javascript function call. If the js: prefix is part if 313 | * the parameter then the 'js:' string is stripped and no conversion 314 | * to string is performed becase js: means that this isn't in fact a 315 | * string but represents a javascript object. 316 | * 317 | * @param mixed $param Can be a php array/object, number or string with 318 | * optional js: prefix. 319 | * 320 | * @return void 321 | */ 322 | public function paramConvert(&$param): void 323 | { 324 | // NOTE: we dont use paramToStr or paramToJSON here reduce the amount 325 | // of function calls. 326 | 327 | if(is_numeric($param)) 328 | { 329 | return; 330 | } 331 | elseif(is_string($param)) 332 | { 333 | if(strlen($param) > 3 && substr($param, 0, 3) == "js:") 334 | { 335 | $param = substr_replace($param, "", 0, 3); 336 | return; 337 | } 338 | 339 | $param = "'" 340 | . str_replace( 341 | ["'", "\n"], 342 | ["\\'", "\\n"], 343 | $param 344 | ) 345 | . "'" 346 | ; 347 | } 348 | elseif(is_array($param) || is_object($param)) 349 | { 350 | $param = json_encode($param); 351 | } 352 | else 353 | { 354 | throw new \Exception( 355 | "Could not properly convert the given parameter" 356 | ); 357 | } 358 | } 359 | 360 | /** 361 | * Converts a parameter to a valid string. 362 | * 363 | * @param string $param 364 | * 365 | * @return void 366 | */ 367 | public function paramToStr(string &$param): void 368 | { 369 | $param = "'" 370 | . str_replace( 371 | ["'", "\n"], 372 | ["\\'", "\\n"], 373 | $param 374 | ) 375 | . "'" 376 | ; 377 | } 378 | 379 | /** 380 | * Converts a parameter to a JSON object. 381 | * 382 | * @param mixed $param 383 | * 384 | * @return void 385 | */ 386 | public function paramToJSON(&$param): void 387 | { 388 | $param = json_encode($param); 389 | } 390 | 391 | /** 392 | * Generate call code chained, same jquery kind of syntax. 393 | * Eg: $("selector").call1().call2().call3(); 394 | * 395 | * @return bool True if chainable turned on or false if not. 396 | */ 397 | public function toggleChainable(): bool 398 | { 399 | if(!$this->identifier) 400 | { 401 | $this->identifier = $this->generateIdentifier(10); 402 | return true; 403 | } 404 | 405 | $this->identifier = ""; 406 | 407 | return false; 408 | } 409 | 410 | /** 411 | * Generate unique identifier string. 412 | * 413 | * @return string 414 | */ 415 | public function generateIdentifier($len): string 416 | { 417 | $text = ""; 418 | 419 | while(strlen($text) < $len) 420 | $text .= str_replace( 421 | array("\$", ".", "/"), 422 | "", 423 | crypt( 424 | uniqid((string)rand($len, intval($len*rand())), true), 425 | uniqid("", true) 426 | ) 427 | ); 428 | 429 | if(strlen($text) > $len) 430 | { 431 | $text = substr($text, 0, $len); 432 | } 433 | 434 | return $text; 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /lib/Puente.php: -------------------------------------------------------------------------------- 1 | instance = self::$next_instance; 66 | self::$next_instance++; 67 | 68 | $this->post_url = $post_url; 69 | 70 | $this->window = new DOM\Window($this); 71 | 72 | $this->local_storage = new DOM\LocalStorage($this); 73 | 74 | $this->session_storage = new DOM\SessionStorage($this); 75 | 76 | $this->puente_storage = new DOM\PuenteStorage($this); 77 | } 78 | 79 | private function getPostLocation(): string 80 | { 81 | if($this->post_url) 82 | return '"' . $this->post_url . '"'; 83 | else 84 | return "window.location.href"; 85 | } 86 | 87 | /** 88 | * Starts a new buffer to store generated code. This is used when 89 | * generating code inside callbacks. 90 | * 91 | * @return void 92 | */ 93 | private function createBuffer(): void 94 | { 95 | $level = $this->code_buffer_next_level; 96 | $this->code_buffer_level = $level; 97 | 98 | $this->code_buffer[$level] = []; 99 | $this->code_buffering = true; 100 | 101 | $this->code_buffer_next_level++; 102 | } 103 | 104 | /** 105 | * Destroy previously created buffer with createBuffer(). 106 | * 107 | * @return void 108 | */ 109 | private function destroyBuffer(): void 110 | { 111 | $level = $this->code_buffer_level; 112 | unset($this->code_buffer[$level]); 113 | 114 | if($this->code_buffer_level > 1) 115 | { 116 | $this->code_buffer_level--; 117 | } 118 | 119 | $this->code_buffer_next_level--; 120 | 121 | if($this->code_buffer_next_level == 1) 122 | { 123 | $this->code_buffering = false; 124 | } 125 | } 126 | 127 | /** 128 | * Clears the active buffer. 129 | * 130 | * @return void 131 | */ 132 | private function clearBuffer(): void 133 | { 134 | if($this->code_buffering) 135 | { 136 | $level = $this->code_buffer_level; 137 | $this->code_buffer[$level] = []; 138 | } 139 | } 140 | 141 | /** 142 | * Helper to generate the code needed to retrieve the apropiate parent 143 | * for a callback. This is needed to execute all parents that will then 144 | * create the child callback. 145 | * 146 | * @param int $id 147 | * @param string $data 148 | * @return array 149 | */ 150 | private function getParents(int $id, string $data="{}"): array 151 | { 152 | if($this->code_buffering) 153 | { 154 | return [ 155 | "decl" => "\nowner=this;" 156 | . "parents.push(parent_id);" 157 | . "parents_data[parent_id] = parent_data;" 158 | . "parent_id=$id;" 159 | . "parent_data=$data;", 160 | "call" => "parents: parents, parents_data: parents_data," 161 | ]; 162 | } 163 | else 164 | { 165 | return [ 166 | "decl" => "\nvar owner=this;" 167 | . "var parents=[];" 168 | . "var parents_data=[];" 169 | . "var parent_id=$id;" 170 | . "var parent_data=$data;", 171 | "call" => "" 172 | ]; 173 | } 174 | 175 | return []; 176 | } 177 | 178 | /** 179 | * Check if a selector has the js: prefix and treats it like an object, 180 | * otherwise it converts it into a string that can be feed to a javascript 181 | * function call. 182 | * 183 | * @param string $selector 184 | * 185 | * @return string 186 | */ 187 | private function parseSelector(string $selector): string 188 | { 189 | if(strlen($selector) > 3 && substr($selector, 0, 3) == "js:") 190 | { 191 | $selector = substr_replace($selector, "", 0, 3); 192 | return $selector; 193 | } 194 | 195 | return $selector = "'" 196 | . str_replace( 197 | ["'", "\n"], 198 | ["\\'", "\\n"], 199 | $selector 200 | ) 201 | . "'" 202 | ; 203 | } 204 | 205 | /** 206 | * Logs in browser console the javascript code sent by callbacks. 207 | * 208 | * @return \Puente\Puente 209 | */ 210 | public function enableDebug(): self 211 | { 212 | $this->debug_mode = true; 213 | 214 | return $this; 215 | } 216 | 217 | /** 218 | * Access a jQuery instance for the given selector. 219 | * 220 | * @param string $selector A valid jQuery selector string or dom object 221 | * using the js: prefix, eg: "js:window", "js:document", etc... 222 | * 223 | * @return JQuery 224 | */ 225 | public function jq(string $selector): JQuery 226 | { 227 | $selector_parsed = $this->parseSelector($selector); 228 | 229 | if($selector == "js:this" && $this->code_buffering) 230 | { 231 | $selector .= $this->current_element; 232 | $selector_parsed = "owner"; 233 | } 234 | 235 | if(!isset($this->elements[$selector])) 236 | { 237 | $varname = "ele".$this->current_element; 238 | 239 | $jquery = new JQuery( 240 | $varname, $this 241 | ); 242 | 243 | $this->addCode("var $varname = jq($selector_parsed);"); 244 | 245 | $this->elements[$selector] = [ 246 | "var" => $varname, 247 | "object" => $jquery 248 | ]; 249 | 250 | $this->current_element++; 251 | 252 | return $jquery; 253 | } 254 | 255 | return $this->elements[$selector]["object"]; 256 | } 257 | 258 | /** 259 | * Add hand crafted javascript code. 260 | * 261 | * @param string $code 262 | * @param string $identifier 263 | * 264 | * @return \Puente\Puente 265 | */ 266 | public function addCode(string $code, string $identifier=""): self 267 | { 268 | if(!$this->code_buffering) 269 | { 270 | if($identifier) 271 | $this->code[$identifier] = $code; 272 | else 273 | $this->code[] = $code; 274 | } 275 | else 276 | { 277 | if($identifier) 278 | $this->code_buffer[$this->code_buffer_level][$identifier] = $code; 279 | else 280 | $this->code_buffer[$this->code_buffer_level][] = $code; 281 | } 282 | 283 | return $this; 284 | } 285 | 286 | /** 287 | * Get hand crafted code stored with a specific identifier. 288 | * 289 | * @param string $code 290 | * 291 | * @return string 292 | */ 293 | public function getCode(string $identifier): string 294 | { 295 | if(!$this->code_buffering) 296 | { 297 | return $this->code[$identifier] ?? ""; 298 | } 299 | 300 | return $this->code_buffer[$this->code_buffer_level][$identifier] 301 | ?? 302 | "" 303 | ; 304 | } 305 | 306 | /** 307 | * Gives you access to the window DOM object. 308 | * 309 | * @return \Puente\DOM\Window 310 | */ 311 | public function window(): DOM\Window 312 | { 313 | return $this->window; 314 | } 315 | 316 | /** 317 | * Gives you access to the localStorage object. 318 | * 319 | * @return \Puente\DOM\LocalStorage 320 | */ 321 | public function localStorage(): DOM\LocalStorage 322 | { 323 | return $this->local_storage; 324 | } 325 | 326 | /** 327 | * Gives you access to the sessionStorage object. 328 | * 329 | * @return \Puente\DOM\SessionStorage 330 | */ 331 | public function sessionStorage(): DOM\SessionStorage 332 | { 333 | return $this->session_storage; 334 | } 335 | 336 | /** 337 | * Gives you access to the Puente array object. 338 | * 339 | * @return \Puente\DOM\PuenteStorage 340 | */ 341 | public function puenteStorage(): DOM\PuenteStorage 342 | { 343 | return $this->puente_storage; 344 | } 345 | 346 | /** 347 | * Generates an ajax callback back to the server. 348 | * 349 | * @param callable $callback 350 | * @param string|array|object $data A valid json string or php array/object. 351 | * 352 | * @return \Puente\Puente 353 | */ 354 | public function addEvent( 355 | callable $callback, $data="{}" 356 | ): self 357 | { 358 | $id = $this->current_event; 359 | $this->current_event++; 360 | 361 | $this->events[$id] = $callback; 362 | 363 | if(is_array($data) || is_object($data)) 364 | { 365 | $data = json_encode($data); 366 | } 367 | 368 | $instance = $this->instance; 369 | $parents = $this->getParents($id, $data); 370 | 371 | $debug = ""; 372 | if($this->debug_mode) 373 | { 374 | $debug .= "console.log(data.code);"; 375 | } 376 | 377 | $code = $parents["decl"] 378 | . "jq.ajax(" 379 | . "{" 380 | . "type: 'POST', " 381 | . "url: ".$this->getPostLocation().", " 382 | . "dataType: 'json', " 383 | . "data: {" 384 | . "puente: $instance, {$parents['call']} " 385 | . "id: '$id', data: $data" 386 | . "}" 387 | . "}" 388 | . ").done(function( data ) {" 389 | . "if(data.error){" 390 | . "alert(data.error);" 391 | . "}else{" 392 | . "eval(data.code);" 393 | . $debug 394 | . "}" 395 | . "}).fail(function(data){" 396 | . "alert('Error Occurred');" 397 | . "});" 398 | ; 399 | 400 | $this->addCode($code); 401 | 402 | return $this; 403 | } 404 | 405 | /** 406 | * Generates an ajax callback that can be used for javascript functions 407 | * that require a callback. 408 | * 409 | * @param string $code JS Code with placeholder for callback function, for 410 | * example: $("element").hide(10, {callback}) where {callback} gets replaced 411 | * with the actual generated callback code. 412 | * @param callable $callback 413 | * @param string|array|object $data A valid json string or php array/pbject. 414 | * For example: "{width: window.innerWidth}" 415 | * 416 | * @return \Puente\Puente 417 | */ 418 | public function addEventCallback( 419 | string $code, callable $callback, $data="{}" 420 | ): self 421 | { 422 | $id = $this->current_event; 423 | $this->current_event++; 424 | 425 | $this->events[$id] = $callback; 426 | 427 | if(is_array($data) || is_object($data)) 428 | { 429 | $data = json_encode($data); 430 | } 431 | 432 | $instance = $this->instance; 433 | $parents = $this->getParents($id, $data); 434 | 435 | $debug = ""; 436 | if($this->debug_mode) 437 | { 438 | $debug .= "console.log(data.code);"; 439 | } 440 | 441 | $callback_code = "function(event){" 442 | . $parents["decl"] 443 | . "jq.ajax(" 444 | . "{" 445 | . "type: 'POST', " 446 | . "url: ".$this->getPostLocation().", " 447 | . "dataType: 'json', " 448 | . "data: {" 449 | . "puente: $instance, {$parents['call']} " 450 | . "id: '$id', data: $data" 451 | . "}" 452 | . "}" 453 | . ").done(function( data ) {" 454 | . "if(data.error){" 455 | . "alert(data.error);" 456 | . "}else{" 457 | . "eval(data.code);" 458 | . $debug 459 | . "}" 460 | . "}).fail(function(data){" 461 | . "alert('Error Occurred');" 462 | . "});}" 463 | ; 464 | 465 | $code = str_replace("{callback}", $callback_code, $code); 466 | 467 | $this->addCode($code); 468 | 469 | return $this; 470 | } 471 | 472 | /** 473 | * Registers an ajax callback for a given element event. 474 | * 475 | * @param string $varname Variable name of the element. 476 | * @param string $type Event type, eg: click, dblclick, etc... 477 | * @param callable $callback 478 | * @param string|array|object $data A valid json string or php array/pbject. 479 | * For example: "{width: window.innerWidth}" 480 | * @param string $identifier Chain the event to the given identifier. 481 | * 482 | * @return \Puente\Puente 483 | */ 484 | public function addElementEvent( 485 | string $varname, 486 | string $type, 487 | callable $callback, 488 | $data="{}", 489 | string $identifier="" 490 | ): self 491 | { 492 | $id = $this->current_event; 493 | $this->current_event++; 494 | 495 | $this->events[$id] = $callback; 496 | 497 | if(is_array($data) || is_object($data)) 498 | { 499 | $data = json_encode($data); 500 | } 501 | 502 | $instance = $this->instance; 503 | $parents = $this->getParents($id, $data); 504 | 505 | $debug = ""; 506 | if($this->debug_mode) 507 | { 508 | $debug .= "console.log(data.code);"; 509 | } 510 | 511 | $varname_include = $varname; 512 | if($identifier) 513 | { 514 | $varname_include = ""; 515 | } 516 | 517 | $code = "$varname_include.on('$type', function(event){" 518 | . $parents["decl"] 519 | . "event.preventDefault();" 520 | . "jq.ajax(" 521 | . "{" 522 | . "type: 'POST', " 523 | . "url: ".$this->getPostLocation().", " 524 | . "dataType: 'json', " 525 | . "data: {" 526 | . "puente: $instance, {$parents['call']} id: '$id', " 527 | . "element: '$varname', data: $data" 528 | . "}" 529 | . "}" 530 | . ").done(function( data ) {" 531 | . "if(data.error){" 532 | . "alert(data.error);" 533 | . "}else{" 534 | . "eval(data.code);" 535 | . $debug 536 | . "}" 537 | . "}).fail(function(data){" 538 | . "alert('Error Occurred');" 539 | . "});" 540 | . "});" 541 | ; 542 | 543 | if(!$identifier) 544 | { 545 | $this->addCode($code); 546 | } 547 | else 548 | { 549 | $current_code = rtrim($this->getCode($identifier), ";"); 550 | 551 | if($current_code) 552 | { 553 | $current_code .= $code; 554 | } 555 | else 556 | { 557 | $current_code = $varname . $code; 558 | } 559 | 560 | $this->addCode($current_code, $identifier); 561 | } 562 | 563 | return $this; 564 | } 565 | 566 | /** 567 | * Process events made from the browser. 568 | * 569 | * @return void 570 | */ 571 | public function listenRequest(): void 572 | { 573 | if( 574 | isset($_POST["puente"]) 575 | && 576 | $_POST["puente"] == $this->instance 577 | ) 578 | { 579 | // This only works if output buffering is enabled with ob_start(), 580 | // the idea is to Remove previously echoed/html output in order to 581 | // return clean json output. 582 | ob_clean(); 583 | 584 | header('Content-Type: application/json; charset=utf-8', true); 585 | 586 | $data = []; 587 | $puente = $this; 588 | 589 | if(isset($_POST["id"])) 590 | { 591 | $id = intval($_POST["id"]); 592 | 593 | if(isset($this->events[$id])) 594 | { 595 | $callback = $this->events[$id]; 596 | 597 | $puente->createBuffer(); 598 | 599 | $callback( 600 | $puente, 601 | $_POST["data"] ?? array() 602 | ); 603 | 604 | $data["code"] = $puente->getPlainCode(); 605 | 606 | $puente->destroyBuffer(); 607 | } 608 | else 609 | { 610 | if(isset($_POST["parents"])) 611 | { 612 | $puente->createBuffer(); 613 | 614 | foreach($_POST["parents"] as $parent) 615 | { 616 | $data = []; 617 | 618 | if( 619 | isset($_POST["parents_data"]) 620 | && 621 | isset($_POST["parents_data"][$parent]) 622 | ) 623 | { 624 | $data = $_POST["parents_data"][$parent]; 625 | } 626 | 627 | $this->events[$parent]( 628 | $puente, $data 629 | ); 630 | } 631 | 632 | $puente->clearBuffer(); 633 | 634 | if(isset($this->events[$id])) 635 | { 636 | $callback = $this->events[$id]; 637 | 638 | $callback( 639 | $puente, 640 | $_POST["data"] ?? array() 641 | ); 642 | 643 | $data["code"] = $puente->getPlainCode(); 644 | } 645 | else 646 | { 647 | $data["error"] = "No child id registered."; 648 | } 649 | 650 | $puente->destroyBuffer(); 651 | } 652 | else 653 | { 654 | $data["error"] = "No id registered."; 655 | } 656 | } 657 | } 658 | else 659 | { 660 | $data["error"] = "No callback id given."; 661 | } 662 | 663 | print json_encode($data); 664 | 665 | exit; 666 | } 667 | } 668 | 669 | /** 670 | * Get the instance ID of the puente. 671 | * 672 | * @return integer 673 | */ 674 | public function getInstanceID(): int 675 | { 676 | return $this->instance; 677 | } 678 | 679 | /** 680 | * Gets the generated code. 681 | * 682 | * @return string 683 | */ 684 | public function getPlainCode(): string 685 | { 686 | $code = ""; 687 | if(!$this->code_buffering) 688 | { 689 | // Initialize global storage of variables. 690 | $storage = ""; 691 | if($this->run_first_time) 692 | { 693 | $storage .= "Puente{$this->instance} = [];\n" 694 | . " " 695 | ; 696 | 697 | $this->run_first_time = false; 698 | } 699 | 700 | $code .= "(function(jq) {\n" 701 | . " " //indentation 702 | . $storage 703 | . implode("\n ", $this->code) 704 | . "\n" 705 | . "})(jQuery);\n" 706 | ; 707 | } 708 | else 709 | { 710 | $code .= "(function(jq) {\n" 711 | . " " //indentation 712 | . implode("\n ", $this->code_buffer[$this->code_buffer_level]) 713 | . "\n" 714 | . "})(jQuery);\n" 715 | ; 716 | } 717 | 718 | return $code; 719 | } 720 | 721 | /** 722 | * Gets the generated code ready to insert into html document. 723 | * 724 | * @return string 725 | */ 726 | public function getExecuteCode(): string 727 | { 728 | $code = "\n" 733 | ; 734 | 735 | return $code; 736 | } 737 | 738 | /** 739 | * Prints ready to use generated code. 740 | * 741 | * @return void 742 | */ 743 | public function executeCode(): void 744 | { 745 | print $this->getExecuteCode(); 746 | } 747 | } -------------------------------------------------------------------------------- /lib/JQuery.php: -------------------------------------------------------------------------------- 1 | toggleChainable(); 33 | } 34 | 35 | /** 36 | * Get an individual jquery instance that can be used on function calls. 37 | * 38 | * @param string $selector 39 | * 40 | * @return JQuery 41 | */ 42 | public static function jq(string $selector): JQuery 43 | { 44 | $util = new self(""); 45 | $util->paramConvert($selector); 46 | 47 | $jquery = new self("jQuery($selector)"); 48 | 49 | return $jquery; 50 | } 51 | 52 | // Dom functions 53 | 54 | /** 55 | * Set the attribute value for the element. 56 | * 57 | * @param string $name 58 | * @param string $value 59 | * 60 | * @return \Puente\JQuery 61 | */ 62 | public function attr(string $name, string $value=""): self 63 | { 64 | if($value) 65 | $this->callMethod("attr", $name, $value); 66 | else 67 | $this->callMethod("attr", $name); 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Remove an attribute from each element in the set of matched elements. 74 | * 75 | * @param string $name 76 | * 77 | * @return \Puente\JQuery 78 | */ 79 | public function removeAttr(string $name): self 80 | { 81 | $this->callMethod("removeAttr", $name); 82 | 83 | return $this; 84 | } 85 | 86 | /** 87 | * Set one or more properties for the set of matched elements. In constrast 88 | * to attr this function allows you to change the internal DOM object 89 | * properties. 90 | * 91 | * @param array|string $properties Eg: ["tagName" => "div"] 92 | * 93 | * @return \Puente\JQuery 94 | */ 95 | public function prop($properties): self 96 | { 97 | $this->callMethod("prop", $properties); 98 | 99 | return $this; 100 | } 101 | 102 | /** 103 | * Remove a property for the set of matched elements. 104 | * 105 | * @param string $name 106 | * 107 | * @return \Puente\JQuery 108 | */ 109 | public function removeProp(string $name): self 110 | { 111 | $this->callMethod("removeProp", $name); 112 | 113 | return $this; 114 | } 115 | 116 | /** 117 | * Sets the html content of the element. 118 | * 119 | * @param string $html 120 | * 121 | * @return \Puente\JQuery 122 | */ 123 | public function html(string $html): self 124 | { 125 | $this->callMethod("html", $html); 126 | 127 | return $this; 128 | } 129 | 130 | /** 131 | * Sets the inner text of the element. 132 | * 133 | * @param string $text 134 | * 135 | * @return \Puente\JQuery 136 | */ 137 | public function text(string $text): self 138 | { 139 | $this->callMethod("text", $text); 140 | 141 | return $this; 142 | } 143 | 144 | /** 145 | * Sets the value of a valid form element. 146 | * 147 | * @param string $value 148 | * 149 | * @return \Puente\JQuery 150 | */ 151 | public function val(string $value): self 152 | { 153 | $this->callMethod("val", $value); 154 | 155 | return $this; 156 | } 157 | 158 | /** 159 | * Inserts content at the end of the selected elements. 160 | * 161 | * @param string $element 162 | * 163 | * @return \Puente\JQuery 164 | */ 165 | public function append(string $element): self 166 | { 167 | $this->callMethod("append", $element); 168 | 169 | return $this; 170 | } 171 | 172 | /** 173 | * Inserts content at the beginning of the selected elements. 174 | * 175 | * @param string $element 176 | * 177 | * @return \Puente\JQuery 178 | */ 179 | public function prepend(string $element): self 180 | { 181 | $this->callMethod("prepend", $element); 182 | 183 | return $this; 184 | } 185 | 186 | /** 187 | * Inserts content after the selected elements. 188 | * 189 | * @param string $element 190 | * 191 | * @return \Puente\JQuery 192 | */ 193 | public function after(string $element): self 194 | { 195 | $this->callMethod("after", $element); 196 | 197 | return $this; 198 | } 199 | 200 | /** 201 | * Inserts content before the selected elements. 202 | * 203 | * @param string $element 204 | * 205 | * @return \Puente\JQuery 206 | */ 207 | public function before(string $element): self 208 | { 209 | $this->callMethod("before", $element); 210 | 211 | return $this; 212 | } 213 | 214 | /** 215 | * Removes the selected element (and its child elements). 216 | * 217 | * @param string $selector Specific child element to remove. 218 | * 219 | * @return \Puente\JQuery 220 | */ 221 | public function remove(string $selector=""): self 222 | { 223 | if($selector) 224 | $this->callMethod("remove", $selector); 225 | else 226 | $this->callMethod("remove"); 227 | 228 | return $this; 229 | } 230 | 231 | /** 232 | * Removes the child elements from the selected element. 233 | * 234 | * @return \Puente\JQuery 235 | */ 236 | public function empty(): JQuery 237 | { 238 | $this->callMethod("empty"); 239 | 240 | return $this; 241 | } 242 | 243 | // Traversing methods 244 | 245 | /** 246 | * Get the parent of each element in the current set of matched elements, 247 | * optionally filtered by a selector. 248 | * 249 | * @param string $selector A string containing a selector expression to 250 | * match elements against. 251 | * 252 | * @return \Puente\JQuery 253 | */ 254 | public function parent(string $selector=""): self 255 | { 256 | if($selector) 257 | $this->callMethod("parent", $selector); 258 | else 259 | $this->callMethod("parent"); 260 | 261 | return $this; 262 | } 263 | 264 | /** 265 | * Get the descendants of each element in the current set of matched 266 | * elements, filtered by a selector. 267 | * 268 | * @param string $selector A string containing a selector expression to 269 | * match elements against. 270 | * 271 | * @return \Puente\JQuery 272 | */ 273 | public function find(string $selector): self 274 | { 275 | $this->callMethod("find", $selector); 276 | 277 | return $this; 278 | } 279 | 280 | /** 281 | * Get the children of each element in the set of matched elements, 282 | * optionally filtered by a selector. 283 | * 284 | * @param string $selector A string containing a selector expression to 285 | * match elements against. 286 | * 287 | * @return \Puente\JQuery 288 | */ 289 | public function children(string $selector=""): self 290 | { 291 | if($selector) 292 | $this->callMethod("children", $selector); 293 | else 294 | $this->callMethod("children"); 295 | 296 | return $this; 297 | } 298 | 299 | /** 300 | * Get the immediately following sibling of each element in the set 301 | * of matched elements filtered by an optional selector. 302 | * 303 | * @param string $selector A string containing a selector expression to 304 | * match elements against. 305 | * 306 | * @return \Puente\JQuery 307 | */ 308 | public function next(string $selector=""): self 309 | { 310 | if($selector) 311 | $this->callMethod("next", $selector); 312 | else 313 | $this->callMethod("next"); 314 | 315 | return $this; 316 | } 317 | 318 | /** 319 | * Get the immediately preceding sibling of each element in the set 320 | * of matched elements filtered by an optional selector. 321 | * 322 | * @param string $selector A string containing a selector expression to 323 | * match elements against. 324 | * 325 | * @return \Puente\JQuery 326 | */ 327 | public function prev(string $selector=""): self 328 | { 329 | if($selector) 330 | $this->callMethod("prev", $selector); 331 | else 332 | $this->callMethod("prev"); 333 | 334 | return $this; 335 | } 336 | 337 | // CSS methods 338 | 339 | /** 340 | * Adds one or more classes to the selected elements. 341 | * 342 | * @param string $class Space separeted list of classes. 343 | * 344 | * @return \Puente\JQuery 345 | */ 346 | public function addClass(string $class): self 347 | { 348 | $this->callMethod("addClass", $class); 349 | 350 | return $this; 351 | } 352 | 353 | /** 354 | * Removes one or more classes from the selected elements. 355 | * 356 | * @param string $class Space separeted list of classes. 357 | * 358 | * @return \Puente\JQuery 359 | */ 360 | public function removeClass(string $class): self 361 | { 362 | $this->callMethod("removeClass", $class); 363 | 364 | return $this; 365 | } 366 | 367 | /** 368 | * Toggles between adding/removing classes from the selected elements. 369 | * 370 | * @param string $class Space separeted list of classes. 371 | * 372 | * @return \Puente\JQuery 373 | */ 374 | public function toggleClass(string $class): self 375 | { 376 | $this->callMethod("toggleClass", $class); 377 | 378 | return $this; 379 | } 380 | 381 | /** 382 | * Sets one or more style properties for the selected elements. 383 | * 384 | * @param array $attributes 385 | * 386 | * @return \Puente\JQuery 387 | */ 388 | public function css(array $attributes): self 389 | { 390 | $this->callMethod("css", $attributes); 391 | 392 | return $this; 393 | } 394 | 395 | /** 396 | * Sets the current coordinates of selected element 397 | * 398 | * @param array $coordinates Can contain position values like top, left, 399 | * bottom and right. Eg: ["top" => 100, "left" => 20] 400 | * 401 | * @return \Puente\JQuery 402 | */ 403 | public function offset(array $coordinates): self 404 | { 405 | $this->callMethod("offset", $coordinates); 406 | 407 | return $this; 408 | } 409 | 410 | /** 411 | * Set the current vertical position of the scroll bar for each of the 412 | * set of matched elements. 413 | * 414 | * @param string $value 415 | * 416 | * @return \Puente\JQuery 417 | */ 418 | public function scrollTop(string $value): self 419 | { 420 | $this->callMethod("scrollTop", $value); 421 | 422 | return $this; 423 | } 424 | 425 | /** 426 | * Set the current horizontal position of the scroll bar for each of the 427 | * set of matched elements. 428 | * 429 | * @param string $value 430 | * 431 | * @return \Puente\JQuery 432 | */ 433 | public function scrollLeft(string $value): self 434 | { 435 | $this->callMethod("scrollLeft", $value); 436 | 437 | return $this; 438 | } 439 | 440 | /** 441 | * Listen for events of the type $event. 442 | * 443 | * @param string $event Type of event. Values can be: click, dblclick, 444 | * change, keyup, keydown, etc... 445 | * @param callable $callback 446 | * @param string|array|object $data The data you want on your callback 447 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 448 | * 449 | * @return \Puente\JQuery 450 | */ 451 | public function on(string $event, callable $callback, $data="{}"): self 452 | { 453 | $this->owner->addElementEvent( 454 | $this->name, 455 | $event, 456 | $callback, 457 | $data 458 | ); 459 | 460 | return $this; 461 | } 462 | 463 | /** 464 | * Execute all handlers and behaviors attached to the matched elements 465 | * for the given event type. 466 | * 467 | * @param string $event A JavaScript event type such as click or submit. 468 | * @param string|array|object $param JSON object to feed into 469 | * each of the invoked events or a php array/object. 470 | * 471 | * @return \Puente\JQuery 472 | */ 473 | public function trigger(string $event, $param=""): self 474 | { 475 | if($param != "") 476 | { 477 | $param = is_string($param) && substr($param, 0, 3) != "js:" ? 478 | "js:$param" : $param 479 | ; 480 | 481 | $this->callMethod("trigger", $event, $param); 482 | } 483 | else 484 | { 485 | $this->callMethod("trigger", $event); 486 | } 487 | 488 | return $this; 489 | } 490 | 491 | // Mouse Events 492 | 493 | /** 494 | * Event called when the element is clicked. 495 | * 496 | * @param callable $callback 497 | * @param string|array|object $data The data you want on your callback 498 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 499 | * 500 | * @return \Puente\JQuery 501 | */ 502 | public function click(callable $callback, $data="{}"): self 503 | { 504 | return $this->on( 505 | "click", 506 | $callback, 507 | $data 508 | ); 509 | } 510 | 511 | /** 512 | * Event called when the element is double clicked. 513 | * 514 | * @param callable $callback 515 | * @param string|array|object $data The data you want on your callback 516 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 517 | * 518 | * @return \Puente\JQuery 519 | */ 520 | public function dblclick(callable $callback, $data="{}"): self 521 | { 522 | return $this->on( 523 | "dblclick", 524 | $callback, 525 | $data 526 | ); 527 | } 528 | 529 | /** 530 | * Event called when the mouse is on top of the element. 531 | * 532 | * @param callable $callback 533 | * @param string|array|object $data The data you want on your callback 534 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 535 | * 536 | * @return \Puente\JQuery 537 | */ 538 | public function mouseenter(callable $callback, $data="{}"): self 539 | { 540 | return $this->on( 541 | "mouseenter", 542 | $callback, 543 | $data 544 | ); 545 | } 546 | 547 | /** 548 | * Event called when the mouse leaves the element. 549 | * 550 | * @param callable $callback 551 | * @param string|array|object $data The data you want on your callback 552 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 553 | * 554 | * @return \Puente\JQuery 555 | */ 556 | public function mouseleave(callable $callback, $data="{}"): self 557 | { 558 | return $this->on( 559 | "mouseleave", 560 | $callback, 561 | $data 562 | ); 563 | } 564 | 565 | // Keypress Events 566 | 567 | /** 568 | * Event called when the element receives a key press that is not a key 569 | * modifier like the ALT, SHIFT, CTRL, ESC, etc... 570 | * 571 | * @param callable $callback 572 | * @param string|array|object $data The data you want on your callback 573 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 574 | * 575 | * @return \Puente\JQuery 576 | */ 577 | public function keypress(callable $callback, $data="{}"): self 578 | { 579 | return $this->on( 580 | "keypress", 581 | $callback, 582 | $data 583 | ); 584 | } 585 | 586 | /** 587 | * Event called when the element receives any key press. 588 | * 589 | * @param callable $callback 590 | * @param string|array|object $data The data you want on your callback 591 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 592 | * 593 | * @return \Puente\JQuery 594 | */ 595 | public function keydown(callable $callback, $data="{}"): self 596 | { 597 | return $this->on( 598 | "keypress", 599 | $callback, 600 | $data 601 | ); 602 | } 603 | 604 | /** 605 | * Event called when a key is released. 606 | * 607 | * @param callable $callback 608 | * @param string|array|object $data The data you want on your callback 609 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 610 | * 611 | * @return \Puente\JQuery 612 | */ 613 | public function keyup(callable $callback, $data="{}"): self 614 | { 615 | return $this->on( 616 | "keyup", 617 | $callback, 618 | $data 619 | ); 620 | } 621 | 622 | // Form Events 623 | 624 | /** 625 | * Event called when the form is submitted. 626 | * 627 | * @param callable $callback 628 | * @param string|array|object $data The data you want on your callback 629 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 630 | * 631 | * @return \Puente\JQuery 632 | */ 633 | public function submit(callable $callback, $data="{}"): self 634 | { 635 | return $this->on( 636 | "submit", 637 | $callback, 638 | $data 639 | ); 640 | } 641 | 642 | /** 643 | * Event called when the form element value changes. 644 | * 645 | * @param callable $callback 646 | * @param string|array|object $data The data you want on your callback 647 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 648 | * 649 | * @return \Puente\JQuery 650 | */ 651 | public function change(callable $callback, $data="{}"): self 652 | { 653 | return $this->on( 654 | "change", 655 | $callback, 656 | $data 657 | ); 658 | } 659 | 660 | /** 661 | * Bind an event handler to the “select” JavaScript event. 662 | * 663 | * @param callable $callback 664 | * @param string|array|object $data The data you want on your callback 665 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 666 | * 667 | * @return \Puente\JQuery 668 | */ 669 | public function select(callable $callback, $data="{}"): self 670 | { 671 | return $this->on( 672 | "select", 673 | $callback, 674 | $data 675 | ); 676 | } 677 | 678 | /** 679 | * Event called when the form element receives focus. 680 | * 681 | * @param callable $callback 682 | * @param string|array|object $data The data you want on your callback 683 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 684 | * 685 | * @return \Puente\JQuery 686 | */ 687 | public function focus(callable $callback, $data="{}"): self 688 | { 689 | return $this->on( 690 | "focus", 691 | $callback, 692 | $data 693 | ); 694 | } 695 | 696 | /** 697 | * Event called when the form element looses focus. 698 | * 699 | * @param callable $callback 700 | * @param string|array|object $data The data you want on your callback 701 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 702 | * 703 | * @return \Puente\JQuery 704 | */ 705 | public function blur(callable $callback, $data="{}"): self 706 | { 707 | return $this->on( 708 | "blur", 709 | $callback, 710 | $data 711 | ); 712 | } 713 | 714 | /** 715 | * Bind an event handler to the "focusin" event. 716 | * 717 | * @param callable $callback 718 | * @param string|array|object $data The data you want on your callback 719 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 720 | * 721 | * @return \Puente\JQuery 722 | */ 723 | public function focusin(callable $callback, $data="{}"): self 724 | { 725 | return $this->on( 726 | "focusin", 727 | $callback, 728 | $data 729 | ); 730 | } 731 | 732 | /** 733 | * Bind an event handler to the "focusout" event. 734 | * 735 | * @param callable $callback 736 | * @param string|array|object $data The data you want on your callback 737 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 738 | * 739 | * @return \Puente\JQuery 740 | */ 741 | public function focusout(callable $callback, $data="{}"): self 742 | { 743 | return $this->on( 744 | "focusout", 745 | $callback, 746 | $data 747 | ); 748 | } 749 | 750 | // Window/Document Events 751 | 752 | /** 753 | * Event called when the element finishes loading. 754 | * 755 | * @param callable $callback 756 | * @param string|array|object $data The data you want on your callback 757 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 758 | * 759 | * @return \Puente\JQuery 760 | */ 761 | public function load(callable $callback, $data="{}"): self 762 | { 763 | return $this->on( 764 | "load", 765 | $callback, 766 | $data 767 | ); 768 | } 769 | 770 | /** 771 | * A function to execute when the DOM is fully loaded. 772 | * 773 | * @param callable $callback 774 | * @param string|array|object $data The data you want on your callback 775 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 776 | * 777 | * @return \Puente\JQuery 778 | */ 779 | public function ready(callable $callback, $data="{}"): self 780 | { 781 | return $this->on( 782 | "ready", 783 | $callback, 784 | $data 785 | ); 786 | } 787 | 788 | /** 789 | * Event called when the element is resized. 790 | * 791 | * @param callable $callback 792 | * @param string|array|object $data The data you want on your callback 793 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 794 | * 795 | * @return \Puente\JQuery 796 | */ 797 | public function resize(callable $callback, $data="{}"): self 798 | { 799 | return $this->on( 800 | "resize", 801 | $callback, 802 | $data 803 | ); 804 | } 805 | 806 | /** 807 | * Event called when the element is scrolled. 808 | * 809 | * @param callable $callback 810 | * @param string|array|object $data The data you want on your callback 811 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 812 | * 813 | * @return \Puente\JQuery 814 | */ 815 | public function scroll(callable $callback, $data="{}"): self 816 | { 817 | return $this->on( 818 | "scroll", 819 | $callback, 820 | $data 821 | ); 822 | } 823 | 824 | /** 825 | * Event called when the element, for example a window is going to be closed. 826 | * 827 | * @param callable $callback 828 | * @param string|array|object $data The data you want on your callback 829 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 830 | * 831 | * @return \Puente\JQuery 832 | */ 833 | public function unload(callable $callback, $data="{}"): self 834 | { 835 | return $this->on( 836 | "unload", 837 | $callback, 838 | $data 839 | ); 840 | } 841 | 842 | // Effects 843 | 844 | /** 845 | * Generic code to run a jQuery effects function. 846 | * 847 | * @param string $effect Name of the jquery effect function. 848 | * @param string $speed Can be: fast, slow or milliseconds amount. 849 | * @param ?callable $callback 850 | * @param string|array|object $data The data you want on your callback 851 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 852 | * 853 | * @return \Puente\JQuery 854 | */ 855 | private function runEffect( 856 | string $effect, string $speed="", ?callable $callback=null, $data="{}" 857 | ): self 858 | { 859 | $speed = $speed === "" ? "fast" : $speed; 860 | 861 | if($callback == null) 862 | { 863 | $this->callMethod($effect, $speed); 864 | } 865 | else 866 | { 867 | $this->paramConvert($speed); 868 | $this->owner->addEventCallback( 869 | $this->name.".$effect($speed, {callback});", 870 | $callback, 871 | $data 872 | ); 873 | } 874 | 875 | return $this; 876 | } 877 | 878 | /** 879 | * Hides the element on the browser. 880 | * 881 | * @param string $speed Can be: fast, slow or milliseconds amount. 882 | * @param ?callable $callback 883 | * @param string|array|object $data The data you want on your callback 884 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 885 | * 886 | * @return \Puente\JQuery 887 | */ 888 | public function hide( 889 | string $speed="", ?callable $callback=null, $data="{}" 890 | ): self 891 | { 892 | return $this->runEffect("hide", $speed, $callback, $data); 893 | } 894 | 895 | /** 896 | * Shows the element on the browser. 897 | * 898 | * @param string $speed Can be: fast, slow or milliseconds amount. 899 | * @param ?callable $callback 900 | * @param string|array|object $data The data you want on your callback 901 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 902 | * 903 | * @return \Puente\JQuery 904 | */ 905 | public function show( 906 | string $speed="", ?callable $callback=null, $data="{}" 907 | ): self 908 | { 909 | return $this->runEffect("show", $speed, $callback, $data); 910 | } 911 | 912 | /** 913 | * Toggles between show/hide. 914 | * 915 | * @param string $speed Can be: fast, slow or milliseconds amount. 916 | * @param ?callable $callback 917 | * @param string|array|object $data The data you want on your callback 918 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 919 | * 920 | * @return \Puente\JQuery 921 | */ 922 | public function toggle( 923 | string $speed="", ?callable $callback=null, $data="{}" 924 | ): self 925 | { 926 | return $this->runEffect("toggle", $speed, $callback, $data); 927 | } 928 | 929 | /** 930 | * Gradually increases the opacity of the element until it is fully visible. 931 | * 932 | * @param string $speed Can be: fast, slow or milliseconds amount. 933 | * @param ?callable $callback 934 | * @param string|array|object $data The data you want on your callback 935 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 936 | * 937 | * @return \Puente\JQuery 938 | */ 939 | public function fadeIn( 940 | string $speed="", ?callable $callback=null, $data="{}" 941 | ): self 942 | { 943 | return $this->runEffect("fadeIn", $speed, $callback, $data); 944 | } 945 | 946 | /** 947 | * Gradually decreases the opacity of the element until it is fully hidden. 948 | * 949 | * @param string $speed Can be: fast, slow or milliseconds amount. 950 | * @param ?callable $callback 951 | * @param string|array|object $data The data you want on your callback 952 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 953 | * 954 | * @return \Puente\JQuery 955 | */ 956 | public function fadeOut( 957 | string $speed="", ?callable $callback=null, $data="{}" 958 | ): self 959 | { 960 | return $this->runEffect("fadeOut", $speed, $callback, $data); 961 | } 962 | 963 | /** 964 | * Toggles between fadeIn and fadeOut. 965 | * 966 | * @param string $speed Can be: fast, slow or milliseconds amount. 967 | * @param ?callable $callback 968 | * @param string|array|object $data The data you want on your callback 969 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 970 | * 971 | * @return \Puente\JQuery 972 | */ 973 | public function fadeToggle( 974 | string $speed="", ?callable $callback=null, $data="{}" 975 | ): self 976 | { 977 | return $this->runEffect("fadeToggle", $speed, $callback, $data); 978 | } 979 | 980 | /** 981 | * Lets you gradually set the opacity to a specific level. 982 | * 983 | * @param string $speed Can be: fast, slow or milliseconds amount. 984 | * @param float $to Level of opacity 985 | * @param ?callable $callback 986 | * @param string|array|object $data The data you want on your callback 987 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 988 | * 989 | * @return \Puente\JQuery 990 | */ 991 | public function fadeTo( 992 | string $speed, float $to, ?callable $callback=null, $data="{}" 993 | ): self 994 | { 995 | $speed = $speed === "" ? "fast" : $speed; 996 | 997 | if($callback == null) 998 | { 999 | $this->callMethod("fadeTo", $speed, $to); 1000 | } 1001 | else 1002 | { 1003 | $this->paramConvert($speed); 1004 | $this->paramConvert($to); 1005 | 1006 | $this->owner->addEventCallback( 1007 | $this->name.".fadeTo($speed, $to, {callback});", 1008 | $callback, 1009 | $data 1010 | ); 1011 | } 1012 | 1013 | return $this; 1014 | } 1015 | 1016 | /** 1017 | * Gradually expands an element until it is visible. 1018 | * 1019 | * @param string $speed Can be: fast, slow or milliseconds amount. 1020 | * @param ?callable $callback 1021 | * @param string|array|object $data The data you want on your callback 1022 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 1023 | * 1024 | * @return \Puente\JQuery 1025 | */ 1026 | public function slideDown( 1027 | string $speed="", ?callable $callback=null, $data="{}" 1028 | ): self 1029 | { 1030 | return $this->runEffect("slideDown", $speed, $callback, $data); 1031 | } 1032 | 1033 | /** 1034 | * Gradually unexpands an element until it is hidden. 1035 | * 1036 | * @param string $speed Can be: fast, slow or milliseconds amount. 1037 | * @param ?callable $callback 1038 | * @param string|array|object $data The data you want on your callback 1039 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 1040 | * 1041 | * @return \Puente\JQuery 1042 | */ 1043 | public function slideUp( 1044 | string $speed="", ?callable $callback=null, $data="{}" 1045 | ): self 1046 | { 1047 | return $this->runEffect("slideUp", $speed, $callback, $data); 1048 | } 1049 | 1050 | /** 1051 | * Toggles between slideDown/slideUp. 1052 | * 1053 | * @param string $speed Can be: fast, slow or milliseconds amount. 1054 | * @param ?callable $callback 1055 | * @param string|array|object $data The data you want on your callback 1056 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 1057 | * 1058 | * @return \Puente\JQuery 1059 | */ 1060 | public function slideToggle( 1061 | string $speed="", ?callable $callback=null, $data="{}" 1062 | ): self 1063 | { 1064 | return $this->runEffect("slideToggle", $speed, $callback, $data); 1065 | } 1066 | 1067 | /** 1068 | * Gradually changes the css attributes of the element to make the 1069 | * desired animation effect. 1070 | * 1071 | * @param string $speed Can be: fast, slow or milliseconds amount. 1072 | * @param ?callable $callback 1073 | * @param string|array|object $data The data you want on your callback 1074 | * as a json string or php array|object, eg: '{width: window.innerWidth}' 1075 | * 1076 | * @return \Puente\JQuery 1077 | */ 1078 | public function animate( 1079 | array $css, string $speed="", ?callable $callback=null, $data="{}" 1080 | ): self 1081 | { 1082 | $speed = $speed === "" ? "fast" : $speed; 1083 | 1084 | if($callback == null) 1085 | { 1086 | $this->callMethod("animate", $css, $speed); 1087 | } 1088 | else 1089 | { 1090 | $this->paramConvert($css); 1091 | $this->paramConvert($speed); 1092 | 1093 | $this->owner->addEventCallback( 1094 | $this->name.".animate($css, $speed, {callback});", 1095 | $callback, 1096 | $data 1097 | ); 1098 | } 1099 | 1100 | return $this; 1101 | } 1102 | 1103 | /** 1104 | * Stop the currently-running animation, remove all queued animations, 1105 | * and complete all animations for the matched elements. 1106 | * 1107 | * @param string $queue The name of the queue in which to stop animations. 1108 | * default is 'fx'. 1109 | * 1110 | * @return \Puente\JQuery 1111 | */ 1112 | public function finish(string $queue=""): self 1113 | { 1114 | if($queue) 1115 | $this->callMethod("finish", $queue); 1116 | else 1117 | $this->callMethod("finish"); 1118 | 1119 | return $this; 1120 | } 1121 | 1122 | /** 1123 | * Stops the animation of current element. 1124 | * 1125 | * @return \Puente\JQuery 1126 | */ 1127 | public function stop(): self 1128 | { 1129 | $this->callMethod("stop"); 1130 | 1131 | return $this; 1132 | } 1133 | } 1134 | --------------------------------------------------------------------------------