diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..488f2e6b7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2010, 2011 the Friendika Project +All rights reserved. + +Redistribution and use in source and binary forms are permitted +provided that the above copyright notice and this paragraph are +duplicated in all such forms and that any documentation, +advertising materials, and other materials related to such +distribution and use acknowledge that the software was developed +by the Friendika Project. The name of the +University may not be used to endorse or promote products derived +from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. diff --git a/README b/README deleted file mode 100644 index 598b6d292..000000000 --- a/README +++ /dev/null @@ -1,86 +0,0 @@ - - ************* - * Friendika * - ************* - - Friendika Communications Server - - http://project.friendika.com - - - Friendika is a web application for managing social communications. Some -would call it a "social network" or "distributed social network". We think -both terms have been over-used, and don't adequately describe Friendika's -capabilities - though Friendika can also fill those roles. - - At its essence, Friendika is a web application which can monitor various -information and social activity streams, and which also lets you participate -in online conversations with friends and associates, using a variety of network -protocols. These are combined into an overview of your various communications -and activities - regardless of network origin. - - Friendika also manages your personal profiles and photo albums and lets -you securely present each of these to specific audiences. Your communications -can be either open and public, or closed and private. You can easily create -"groups" of contacts with which you can partition your conversations into -private social circles, and which cannot be seen outside the circle. - - Friendika is decentralised. Any account on any Friendika server can connect -with any account on any other Friendika server. You can also connect to and -interact directly with friends on Facebook, Status.Net, and other federated -social web services (e.g. identi.ca, GNU-Social, etc.). - - Outgoing communications can be directed to Friendika, existing accounts on -Facebook and Twitter, federated social web providers - or even delivered to -email contacts. - - Incoming data streams aren't limited to traditional social networks. -They may include most any service which provides a syndication feed (both RSS -and Atom). This allows you to view communications from friends in other -diverse social networks - such as Diaspora, Google Buzz, and millions of -blogs, news services, and other websites. You can also import -contacts from (and write to) anybody that is accessible from your email -INBOX and view them in your social stream. Over time we will try to -build two-way bridges to other services so that you can freely -interact in both directions with anybody on an accessible network that -allows it. - - Communications between Friendika servers are private and encrypted, -using military grade encryption - and require mutual identity provenance -before any data is exchanged. These same crypto mechanisms provide remote -password-less authentication; allowing you to post to profiles and view private -photo collections on other servers - without encountering any login and/or -authorisation dialogues when visiting these sites. - - Friendika has no boundaries and no central ownership of the data generated -within the network. Anybody with a commodity PHP/MySQL web server or hosting -account can provide a server, and each individual server can then support -up to several thousand participating members - each with their own unique -communication and privacy needs. This allows Friendika to scale to global -levels and mimics the decentralised architecture of the web itself. - - If you are creating a website which requires social interaction, Friendika -can also take the place of blog software, forum software and feed readers, and -also provide individualised communications and content management - or -simply be used as an alternative to traditional "monolithic" social networks. - - Friendika is also free - in every sense of the word. - - Choose freedom - join us. - - Find out more about the project at http://project.friendika.com - - ******************* - Friendika Demo Site - ******************* - - http://demo.friendika.com - - ******************* - Friendika Downloads - ******************* - - http://github.com/friendika/friendika/tarball/master - - - diff --git a/addon/README b/addon/README deleted file mode 100644 index fb1c6340a..000000000 --- a/addon/README +++ /dev/null @@ -1,186 +0,0 @@ -Friendika Addon/Plugin development - -This is an early specification and hook details may be subject to change. - -Please see the sample addon 'randplace' for a working example of using these features. - - -You must register plugins with the system in the .htconfig.php file. - -$a->config['system']['addon'] = 'plugin1name, plugin2name, another_name'; - -Plugin names cannot contain spaces and are used as filenames. - - -Register your plugin hooks during installation. - - register_hook($hookname, $file, $function); - - $hookname is a string and corresponds to a known Friendika hook - $file is a pathname relative to the top-level Friendika directory. - This *should* be 'addon/plugin_name/plugin_name.php' in most cases. - $function is a string and is the name of the function which will be executed - when the hook is called. - - -Your hook functions will be called with at least one and possibly two arguments - - function myhook_function(&$a, &$b) { - - - } - -If you wish to make changes to the calling data, you must declare them as -reference variables (with '&') during function declaration. - -$a is the Friendika 'App' class - which contains a wealth of information -about the current state of Friendika, such as which module has been called, -configuration info, the page contents at the point the hook was invoked, profile -and user information, etc. It is recommeded you call this '$a' to match its usage -elsewhere. - -$b can be called anything you like. This is information which is specific to the hook -currently being processed, and generally contains information that is being immediately -processed or acted on that you can use, display, or alter. Remember to declare it with -'&' if you wish to alter it. - - -Current hooks: - -'authenticate' - called when a user attempts to login. - $b is an array - 'username' => the supplied username - 'password' => the supplied password - 'authenticated' => set this to non-zero to authenticate the user. - 'user_record' => successful authentication must also return a valid user record from the database - - -'logged_in' - called after a user has successfully logged in. - $b contains the $a->user array - - -'display_item' - called when formatting a post for display. - $b is an array - 'item' => The item (array) details pulled from the database - 'output' => the (string) HTML representation of this item prior to adding it - to the page - -'post_local' - called when a status post or comment is entered on the local system - $b is the item array of the information to be stored in the database - {Please note: body contents are bbcode - not HTML) - -'post_local_end' - called when a local status post or comment has been stored on the local system - $b is the item array of the information which has just been stored in the database - {Please note: body contents are bbcode - not HTML) - - -'post_remote' - called when receiving a post from another source. This may also be used - to post local activity or system generated messages. - $b is the item array of information to be stored in the database and the item - body is bbcode. - -'settings_form' - called when generating the HTML for the user Settings page - $b is the (string) HTML of the settings page before the final '' tag. - -'settings_post' - called when the Settings pages are submitted. - $b is the $_POST array - -'plugin_settings' - called when generating the HTML for the addon settings page - $b is the (string) HTML of the addon settings page before the final '' tag. - -'plugin_settings_post' - called when the Addon Settings pages are submitted. - $b is the $_POST array - -'profile_post' - called when posting a profile page. - $b is the $_POST array - -'profile_edit' - called prior to output of profile edit page - $b is array - 'profile' => profile (array) record from the database - 'entry' => the (string) HTML of the generated entry - -'profile_advanced' - called when the HTML is generated for the 'Advanced profile', - corresponding to the 'Profile' tab within a person's profile page. - $b is the (string) HTML representation of the generated profile - -'directory_item' - called from the Directory page when formatting an item for display - $b is an array - 'contact' => contact (array) record for the person from the database - 'entry' => the (string) HTML of the generated entry - -'profile_sidebar_enter' - called prior to generating the sidebar "short" profile for a page - $b is (array) the person's profile array - -'profile_sidebar' - called when generating the sidebar "short" profile for a page - $b is an array - 'profile' => profile (array) record for the person from the database - 'entry' => the (string) HTML of the generated entry - -'contact_block_end' - called when formatting the block of contacts/friends on a - profile sidebar has completed - $b is an array - 'contacts' => contact array of entries - 'output' => the (string) generated HTML of the contact block - -'bbcode' - called during conversion of bbcode to html - $b is (string) converted text - -'html2bbcode' - called during conversion of html to bbcode (e.g. remote message posting) - $b is (string) converted text - - -'page_header' - called after building the page navigation section - $b is (string) HTML of nav region - - -'personal_xrd' - called prior to output of personal XRD file. - $b is an array - 'user' => the user record for the person - 'xml' => the complete XML to be output - - -'home_content' - called prior to output home page content, shown to unlogged users - $b is (string) HTML of section region - -'contact_edit' - called when editing contact details on an individual from the Contacts page - $b is (array) - 'contact' => contact record (array) of target contact - 'output' => the (string) generated HTML of the contact edit page - -'contact_edit_post' - called when posting the contact edit page - $b is the $_POST array - -'init_1' - called just after DB has been opened and before session start - $b is not used or passed - -'page_end' - called after HTML content functions have completed - $b is (string) HTML of content div - -'jot_plugin' - add tools to jot toolbar - $b is (string) HTML for tool icon - - -*** = subject to change - - - - - -Not yet documented: - -'atom_feed' *** - -'atom_feed_end' *** - -'parse_atom' *** - -'atom_author' *** - -'atom_entry' *** - -'parse_link' *** - - - - - diff --git a/addon/calc/calc.php b/addon/calc/calc.php deleted file mode 100644 index 8c079dc7a..000000000 --- a/addon/calc/calc.php +++ /dev/null @@ -1,363 +0,0 @@ - - */ - - -function calc_install() { - register_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); -} - -function calc_uninstall() { - unregister_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); - -} - -function calc_app_menu($a,&$b) { - $b['app_menu'] .= '
Calculator
'; -} - - -function calc_module() {} - - - - -function calc_init($a) { - -$x = <<< EOT - - - -EOT; -$a->page['htmlhead'] .= $x; -} - -function calc_content($app) { - -$o = ''; - -$o .= <<< EOT - -

Calculator

-

- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - -
- -EOT; -return $o; - -} diff --git a/addon/convert/UnitConvertor.php b/addon/convert/UnitConvertor.php deleted file mode 100644 index d7933a8fb..000000000 --- a/addon/convert/UnitConvertor.php +++ /dev/null @@ -1,283 +0,0 @@ - | -// | Co-authored by : CVH, Chris Hansel | -// +----------------------------------------------------------------------+ -// -// $Id: UnitConvertor.php,v 1.00 2002/02/20 11:40:00 stasokhvat Exp $ - -/** -* UnitConvertor is able to convert between different units and currencies. -* -* @author Stanislav Okhvat -* @version $Id: UnitConvertor.php,v 1.00 2002/03/01 17:00:00 stasokhvat Exp $ -* @package UnitConvertor -* @access public -* @history 01.03.2002 Implemented the code for regular and offset-based -* conversions -* -* 13.12.2004 -* By Chris Hansel (CVH): changed getConvSpecs in order to have it look up -* intermediary conversions (also see comments in check_key). -* -* Intermediary conversions are useful when no conversion ratio is specified -* between two units when we calculate between the two. For example, we want -* to convert between Fahrenheit and Kelvin, and we have only -* specified how to convert Centigrade<->Fahrenheit and -* Centigrade<->Kelvin. While a direct (Fahrenheit->Kelvin) or -* reverse (Kelvin->Fahrenheit) lookups fail, looking for an intermediary -* unit linking the two (Centigrade) helps us do the conversion. -* -* 13.12.2004 -* Chris Hansel (CVH): $to_array argument of addConversion method can now -* contain units as 'unit1/unit2/unit3', when all units stand for the same -* thing. See examples in unitconv.php -*/ -class UnitConvertor -{ - /** - * Stores conversion ratios. - * - * @var array - * @access private - */ - var $conversion_table = array(); - - /** - * Decimal point character (default is "." - American - set in constructor). - * - * @var string - * @access private - */ - var $decimal_point; - - /** - * Thousands separator (default is "," - American - set in constructor). - * - * @var string - * @access private - */ - var $thousand_separator; - - /** - * For future use - * - * @var array - * @access private - */ - var $bases = array(); - - /** - * Constructor. Initializes the UnitConvertor object with the most important - * properties. - * - * @param string decimal point character - * @param string thousand separator character - * @return void - * @access public - */ - function UnitConvertor($dec_point = '.', $thousand_sep = ',') - { - $this->decimal_point = $dec_point; - $this->thousand_separator = $thousand_sep; - - } // end func UnitConvertor - - /** - * Adds a conversion ratio to the conversion table. - * - * @param string the name of unit from which to convert - * @param array array( - * "pound"=>array("ratio"=>'', "offset"=>'') - * ) - * "pound" - name of unit to set conversion ration to - * "ratio" - 'double' conversion ratio which, when - * multiplied by the number of $from_unit units produces - * the result - * "offset" - an offset from 0 which will be added to - * the result when converting (needed for temperature - * conversions and defaults to 0). - * @return boolean true if successful, false otherwise - * @access public - */ - function addConversion($from_unit, $to_array) - { - if (!isset($this->conversion_table[$from_unit])) { - while(list($key, $val) = each($to_array)) - { - if (strstr($key, '/')) - { - $to_units = explode('/', $key); - foreach ($to_units as $to_unit) - { - $this->bases[$from_unit][] = $to_unit; - - if (!is_array($val)) - { - $this->conversion_table[$from_unit."_".$to_unit] = array("ratio"=>$val, "offset"=>0); - } - else - { - $this->conversion_table[$from_unit."_".$to_unit] = - array( - "ratio"=>$val['ratio'], - "offset"=>(isset($val['offset']) ? $val['offset'] : 0) - ); - } - } - } - else - { - $this->bases[$from_unit][] = $key; - - if (!is_array($val)) - { - $this->conversion_table[$from_unit."_".$key] = array("ratio"=>$val, "offset"=>0); - } - else - { - $this->conversion_table[$from_unit."_".$key] = - array( - "ratio"=>$val['ratio'], - "offset"=>(isset($val['offset']) ? $val['offset'] : 0) - ); - } - } - } - return true; - } - return false; - - } // end func addConversion - - /** - * Converts from one unit to another using specified precision. - * - * @param double value to convert - * @param string name of the source unit from which to convert - * @param string name of the target unit to which we are converting - * @param integer double precision of the end result - * @return void - * @access public - */ - function convert($value, $from_unit, $to_unit, $precision) - { - if ($this->getConvSpecs($from_unit, $to_unit, $value, $converted )) - { - return number_format($converted , (int)$precision, $this->decimal_point, $this->thousand_separator); - } else { - return false; - } - } // end func - - /** - * CVH : changed this Function getConvSpecs in order to have it look up - * intermediary Conversions from the - * "base" unit being that one that has the highest hierarchical order in one - * "logical" Conversion_Array - * when taking $conv->addConversion('km', - * array('meter'=>1000, 'dmeter'=>10000, 'centimeter'=>100000, - * 'millimeter'=>1000000, 'mile'=>0.62137, 'naut.mile'=>0.53996, - * 'inch(es)/zoll'=>39370, 'ft/foot/feet'=>3280.8, 'yd/yard'=>1093.6)); - * "km" would be the logical base unit for all units of dinstance, thus, - * if the function fails to find a direct or reverse conversion in the table - * it is only logical to suspect that if there is a chance - * converting the value it only is via the "base" unit, and so - * there is not even a need for a recursive search keeping the perfomance - * acceptable and the ressource small... - * - * CVH check_key checks for a key in the Conversiontable and returns a value - */ - function check_key( $key) { - if ( array_key_exists ($key,$this->conversion_table)) { - if (! empty($this->conversion_table[$key])) { - return $this->conversion_table[$key]; - } - } - return false; - } - - /** - * Key function. Finds the conversion ratio and offset from one unit to another. - * - * @param string name of the source unit from which to convert - * @param string name of the target unit to which we are converting - * @param double conversion ratio found. Returned by reference. - * @param double offset which needs to be added (or subtracted, if negative) - * to the result to convert correctly. - * For temperature or some scientific conversions, - * i.e. Fahrenheit -> Celcius - * @return boolean true if ratio and offset are found for the supplied - * units, false otherwise - * @access private - */ - function getConvSpecs($from_unit, $to_unit, $value, &$converted) - { - $key = $from_unit."_".$to_unit; - $revkey = $to_unit."_".$from_unit; - $found = false; - if ($ct_arr = $this->check_key($key)) { - // Conversion Specs found directly - $ratio = (double)$ct_arr['ratio']; - $offset = $ct_arr['offset']; - $converted = (double)(($value * $ratio)+ $offset); - - return true; - } // not found in direct order, try reverse order - elseif ($ct_arr = $this->check_key($revkey)) { - $ratio = (double)(1/$ct_arr['ratio']); - $offset = -$ct_arr['offset']; - $converted = (double)(($value + $offset) * $ratio); - - return true; - } // not found test for intermediary conversion - else { - // return ratio = 1 if keyparts match - if ($key == $revkey) { - $ratio = 1; - $offset = 0; - $converted = $value; - return true; - } - // otherwise search intermediary - reset($this->conversion_table); - while (list($convk, $i1_value) = each($this->conversion_table)) { - // split the key into parts - $keyparts = preg_split("/_/",$convk); - // return ratio = 1 if keyparts match - - // Now test if either part matches the from or to unit - if ($keyparts[1] == $to_unit && ($i2_value = $this->check_key($keyparts[0]."_".$from_unit))) { - // an intermediary $keyparts[0] was found - // now let us put things together intermediary 1 and 2 - $converted = (double)(((($value - $i2_value['offset']) / $i2_value['ratio']) * $i1_value['ratio'])+ $i1_value['offset']); - - $found = true; - - } elseif ($keyparts[1] == $from_unit && ($i2_value = $this->check_key($keyparts[0]."_".$to_unit))) { - // an intermediary $keyparts[0] was found - // now let us put things together intermediary 2 and 1 - $converted = (double)(((($value - $i1_value['offset']) / $i1_value['ratio']) + $i2_value['offset']) * $i2_value['ratio']); - - $found = true; - } - } - return $found; - } - - } // end func getConvSpecs - -} // end class UnitConvertor -?> \ No newline at end of file diff --git a/addon/convert/convert.php b/addon/convert/convert.php deleted file mode 100644 index 7a4c90a53..000000000 --- a/addon/convert/convert.php +++ /dev/null @@ -1,228 +0,0 @@ - - */ - -function convert_install() { - register_hook('app_menu', 'addon/convert/convert.php', 'convert_app_menu'); -} - -function convert_uninstall() { - unregister_hook('app_menu', 'addon/convert/convert.php', 'convert_app_menu'); -} - -function convert_app_menu($a,&$b) { - $b['app_menu'] .= ''; -} - - -function convert_module() {} - - - - - - - -function convert_content($app) { - -include("UnitConvertor.php"); - - class TP_Converter extends UnitConvertor { - function TP_Converter($lang = "en") - { - if ($lang != 'en' ) { - $dec_point = '.'; $thousand_sep = "'"; - } else { - $dec_point = '.'; $thousand_sep = ","; - } - - $this->UnitConvertor($dec_point , $thousand_sep ); - - } // end func UnitConvertor - - function find_base_unit($from,$to) { - while (list($skey,$sval) = each($this->bases)) { - if ($skey == $from || $to == $skey || in_array($to,$sval) || in_array($from,$sval)) { - return $skey; - } - } - return false; - } - - function getTable($value, $from_unit, $to_unit, $precision) { - - if ($base_unit = $this->find_base_unit($from_unit,$to_unit)) { - - // A baseunit was found now lets convert from -> $base_unit - - $cell ['value'] = $this->convert($value, $from_unit, $base_unit, $precision)." ".$base_unit; - $cell ['class'] = ($base_unit == $from_unit || $base_unit == $to_unit) ? "framedred": ""; - $cells[] = $cell; - // We now have the base unit and value now lets produce the table; - while (list($key,$val) = each($this->bases[$base_unit])) { - $cell ['value'] = $this->convert($value, $from_unit, $val, $precision)." ".$val; - $cell ['class'] = ($val == $from_unit || $val == $to_unit) ? "framedred": ""; - $cells[] = $cell; - } - - $cc = count($cells); - $string = ""; - $string .= ""; - $i=0; - foreach ($cells as $cell) { - if ($i==0) { - $string .= ""; - $i++; - } else { - $string .= ""; - } - } - $string .= "
$value $from_unit".$cell['value']."
".$cell['value']."
"; - return $string; - } - - } -} - - -$conv = new TP_Converter('en'); - - -$conversions = array( - 'Temperature'=>array('base' =>'Celsius', - 'conv'=>array( - 'Fahrenheit'=>array('ratio'=>1.8, 'offset'=>32), - 'Kelvin'=>array('ratio'=>1, 'offset'=>273), - 'Reaumur'=>0.8 - ) - ), - 'Weight' => array('base' =>'kg', - 'conv'=>array( - 'g'=>1000, - 'mg'=>1000000, - 't'=>0.001, - 'grain'=>15432, - 'oz'=>35.274, - 'lb'=>2.2046, - 'cwt(UK)' => 0.019684, - 'cwt(US)' => 0.022046, - 'ton (US)' => 0.0011023, - 'ton (UK)' => 0.0009842 - ) - ), - 'Distance' => array('base' =>'km', - 'conv'=>array( - 'm'=>1000, - 'dm'=>10000, - 'cm'=>100000, - 'mm'=>1000000, - 'mile'=>0.62137, - 'naut.mile'=>0.53996, - 'inch(es)'=>39370, - 'ft'=>3280.8, - 'yd'=>1093.6, - 'furlong'=>4.970969537898672, - 'fathom'=>546.8066491688539 - ) - ), - 'Area' => array('base' =>'km 2', - 'conv'=>array( - 'ha'=>100, - 'acre'=>247.105, - 'm 2'=>pow(1000,2), - 'dm 2'=>pow(10000,2), - 'cm 2'=>pow(100000,2), - 'mm 2'=>pow(1000000,2), - 'mile 2'=>pow(0.62137,2), - 'naut.miles 2'=>pow(0.53996,2), - 'in 2'=>pow(39370,2), - 'ft 2'=>pow(3280.8,2), - 'yd 2'=>pow(1093.6,2), - ) - ), - 'Volume' => array('base' =>'m 3', - 'conv'=>array( - 'in 3'=>61023.6, - 'ft 3'=>35.315, - 'cm 3'=>pow(10,6), - 'dm 3'=>1000, - 'litre'=>1000, - 'hl'=>10, - 'yd 3'=>1.30795, - 'gal(US)'=>264.172, - 'gal(UK)'=>219.969, - 'pint' => 2113.376, - 'quart' => 1056.688, - 'cup' => 4266.753, - 'fl oz' => 33814.02, - 'tablespoon' => 67628.04, - 'teaspoon' => 202884.1, - 'pt (UK)'=>1000/0.56826, - 'barrel petroleum'=>1000/158.99, - 'Register Tons'=>2.832, - 'Ocean Tons'=>1.1327 - ) - ), - 'Speed' =>array('base' =>'kmph', - 'conv'=>array( - 'mps'=>0.0001726031, - 'milesph'=>0.62137, - 'knots'=>0.53996, - 'mach STP'=>0.0008380431, - 'c (warp)'=>9.265669e-10 - ) - ) -); - - -while (list($key,$val) = each($conversions)) { - $conv->addConversion($val['base'], $val['conv']); - $list[$key][] = $val['base']; - while (list($ukey,$uval) = each($val['conv'])) { - $list[$key][] = $ukey; - } -} - - $o .= '

Unit Conversions

'; - - - if (isset($_POST['from_unit']) && isset($_POST['value'])) { - $_POST['value'] = $_POST['value'] + 0; - - - $o .= ($conv->getTable($_POST['value'], $_POST['from_unit'], $_POST['to_unit'], 5))."

"; - } else { - $o .= "

Select:

"; - } - - if(isset($_POST['value'])) - $value = $_POST['value']; - else - $value = ''; - - $o .= '
'; - $o .= ''; - $o .= ''; - - $o .= '
'; - - return $o; -} diff --git a/addon/facebook/README b/addon/facebook/README deleted file mode 100644 index 325f18dd1..000000000 --- a/addon/facebook/README +++ /dev/null @@ -1,39 +0,0 @@ -Installing the Friendika/Facebook connector - -1. register an API key for your site from developer.facebook.com - a. We'd be very happy if you include "Friendika" in the application name - to increase name recognition. The Friendika icons are also present - in the images directory and may be uploaded as a Facebook app icon. - Use images/friendika-16.jpg for the Icon and images/friendika-128.jpg for the Logo. - b. The url should be your site URL with a trailing slash. - You may use http://portal.friendika.com/privacy as the privacy policy - URL unless your site has different requirements, and - http://portal.friendika.com as the Terms of Service URL unless - you have different requirements. (Friendika is a software application - and does not require Terms of Service, though your installation of it might). - c. Set the following values in your .htconfig.php file - $a->config['facebook']['appid'] = 'xxxxxxxxxxx'; - $a->config['facebook']['appsecret'] = 'xxxxxxxxxxxxxxx'; - Replace with the settings Facebook gives you. - d. Navigate to Set Web->Site URL & Domain -> Website Settings. Set Site URL - to yoursubdomain.yourdomain.com. Set Site Domain to your yourdomain.com. -2. Enable the facebook plugin by including it in .htconfig.php - e.g. - $a->config['system']['addon'] = 'plugin1,plugin2,facebook'; -3. Visit the Facebook Settings section of the "Settings->Plugin Settings" page. - and click 'Install Facebook Connector'. -4. This will ask you to login to Facebook and grant permission to the - plugin to do its stuff. Allow it to do so. -5. You're done. To turn it off visit the Plugin Settings page again and - 'Remove Facebook posting'. - -Vidoes and embeds will not be posted if there is no other content. Links -and images will be converted to a format suitable for the Facebook API and -long posts truncated - with a link to view the full post. - -Facebook contacts will not be able to view private photos, as they are not able to -authenticate to your site to establish identity. We will address this -in a future release. - -Info: please make sure that you understand all aspects due to Friendika's -default licence which is: Creative Commons Attribution 3.0 (further info: -http://creativecommons.org/licenses/by/3.0/ ) diff --git a/addon/facebook/facebook.css b/addon/facebook/facebook.css deleted file mode 100644 index 0c164331e..000000000 --- a/addon/facebook/facebook.css +++ /dev/null @@ -1,13 +0,0 @@ - -#facebook-enable-wrapper { - margin-top: 20px; -} - -#facebook-disable-wrapper { - margin-top: 20px; -} - -#facebook-post-default-form input { - margin-top: 20px; - margin-right: 20px; -} \ No newline at end of file diff --git a/addon/facebook/facebook.php b/addon/facebook/facebook.php deleted file mode 100644 index 7ffdaffac..000000000 --- a/addon/facebook/facebook.php +++ /dev/null @@ -1,1059 +0,0 @@ - - */ - -/** - * Installing the Friendika/Facebook connector - * - * 1. register an API key for your site from developer.facebook.com - * a. We'd be very happy if you include "Friendika" in the application name - * to increase name recognition. The Friendika icons are also present - * in the images directory and may be uploaded as a Facebook app icon. - * Use images/friendika-16.jpg for the Icon and images/friendika-128.jpg for the Logo. - * b. The url should be your site URL with a trailing slash. - * You may use http://portal.friendika.com/privacy as the privacy policy - * URL unless your site has different requirements, and - * http://portal.friendika.com as the Terms of Service URL unless - * you have different requirements. (Friendika is a software application - * and does not require Terms of Service, though your installation of it might). - * c. Set the following values in your .htconfig.php file - * $a->config['facebook']['appid'] = 'xxxxxxxxxxx'; - * $a->config['facebook']['appsecret'] = 'xxxxxxxxxxxxxxx'; - * Replace with the settings Facebook gives you. - * d. Navigate to Set Web->Site URL & Domain -> Website Settings. Set - * Site URL to yoursubdomain.yourdomain.com. Set Site Domain to your - * yourdomain.com. - * 2. Enable the facebook plugin by including it in .htconfig.php - e.g. - * $a->config['system']['addon'] = 'plugin1,plugin2,facebook'; - * 3. Visit the Facebook Settings section of the "Settings->Plugin Settings" page. - * and click 'Install Facebook Connector'. - * 4. This will ask you to login to Facebook and grant permission to the - * plugin to do its stuff. Allow it to do so. - * 5. You're done. To turn it off visit the Plugin Settings page again and - * 'Remove Facebook posting'. - * - * Vidoes and embeds will not be posted if there is no other content. Links - * and images will be converted to a format suitable for the Facebook API and - * long posts truncated - with a link to view the full post. - * - * Facebook contacts will not be able to view private photos, as they are not able to - * authenticate to your site to establish identity. We will address this - * in a future release. - */ - -define('FACEBOOK_MAXPOSTLEN', 420); - - -function facebook_install() { - register_hook('post_local_end', 'addon/facebook/facebook.php', 'facebook_post_hook'); - register_hook('jot_networks', 'addon/facebook/facebook.php', 'facebook_jot_nets'); - register_hook('plugin_settings', 'addon/facebook/facebook.php', 'facebook_plugin_settings'); - register_hook('cron', 'addon/facebook/facebook.php', 'facebook_cron'); - register_hook('queue_predeliver', 'addon/facebook/facebook.php', 'fb_queue_hook'); -} - - -function facebook_uninstall() { - unregister_hook('post_local_end', 'addon/facebook/facebook.php', 'facebook_post_hook'); - unregister_hook('jot_networks', 'addon/facebook/facebook.php', 'facebook_jot_nets'); - unregister_hook('plugin_settings', 'addon/facebook/facebook.php', 'facebook_plugin_settings'); - unregister_hook('cron', 'addon/facebook/facebook.php', 'facebook_cron'); - unregister_hook('queue_predeliver', 'addon/facebook/facebook.php', 'fb_queue_hook'); -} - - -/* declare the facebook_module function so that /facebook url requests will land here */ - -function facebook_module() {} - - - -/* If a->argv[1] is a nickname, this is a callback from Facebook oauth requests. */ - -function facebook_init(&$a) { - - if($a->argc != 2) - return; - $nick = $a->argv[1]; - if(strlen($nick)) - $r = q("SELECT `uid` FROM `user` WHERE `nickname` = '%s' LIMIT 1", - dbesc($nick) - ); - if(! count($r)) - return; - - $uid = $r[0]['uid']; - $auth_code = (($_GET['code']) ? $_GET['code'] : ''); - $error = (($_GET['error_description']) ? $_GET['error_description'] : ''); - - - if($error) - logger('facebook_init: Error: ' . $error); - - if($auth_code && $uid) { - - $appid = get_config('facebook','appid'); - $appsecret = get_config('facebook', 'appsecret'); - - $x = fetch_url('https://graph.facebook.com/oauth/access_token?client_id=' - . $appid . '&client_secret=' . $appsecret . '&redirect_uri=' - . urlencode($a->get_baseurl() . '/facebook/' . $nick) - . '&code=' . $auth_code); - - logger('facebook_init: returned access token: ' . $x, LOGGER_DATA); - - if(strpos($x,'access_token=') !== false) { - $token = str_replace('access_token=', '', $x); - if(strpos($token,'&') !== false) - $token = substr($token,0,strpos($token,'&')); - set_pconfig($uid,'facebook','access_token',$token); - set_pconfig($uid,'facebook','post','1'); - if(get_pconfig($uid,'facebook','no_linking') === false) - set_pconfig($uid,'facebook','no_linking',1); - fb_get_self($uid); - fb_get_friends($uid); - fb_consume_all($uid); - - } - - } - -} - - -function fb_get_self($uid) { - $access_token = get_pconfig($uid,'facebook','access_token'); - if(! $access_token) - return; - $s = fetch_url('https://graph.facebook.com/me/?access_token=' . $access_token); - if($s) { - $j = json_decode($s); - set_pconfig($uid,'facebook','self_id',(string) $j->id); - } -} - - - -function fb_get_friends($uid) { - - $r = q("SELECT `id` FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", - intval($uid) - ); - if(! count($r)) - return; - - $access_token = get_pconfig($uid,'facebook','access_token'); - - $no_linking = get_pconfig($uid,'facebook','no_linking'); - if($no_linking) - return; - - if(! $access_token) - return; - $s = fetch_url('https://graph.facebook.com/me/friends?access_token=' . $access_token); - if($s) { - logger('facebook: fb_get_friends: ' . $s, LOGGER_DATA); - $j = json_decode($s); - logger('facebook: fb_get_friends: json: ' . print_r($j,true), LOGGER_DATA); - if(! $j->data) - return; - foreach($j->data as $person) { - $s = fetch_url('https://graph.facebook.com/' . $person->id . '?access_token=' . $access_token); - if($s) { - $jp = json_decode($s); - logger('fb_get_friends: info: ' . print_r($jp,true), LOGGER_DATA); - - // always use numeric link for consistency - - $jp->link = 'http://facebook.com/profile.php?id=' . $person->id; - - // check if we already have a contact - - $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `url` = '%s' LIMIT 1", - intval($uid), - dbesc($jp->link) - ); - - if(count($r)) { - - // check that we have all the photos, this has been known to fail on occasion - - if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro'])) { - require_once("Photo.php"); - - $photos = import_profile_photo('https://graph.facebook.com/' . $jp->id . '/picture', $uid, $r[0]['id']); - - $r = q("UPDATE `contact` SET `photo` = '%s', - `thumb` = '%s', - `micro` = '%s', - `name-date` = '%s', - `uri-date` = '%s', - `avatar-date` = '%s' - WHERE `id` = %d LIMIT 1 - ", - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($r[0]['id']) - ); - } - continue; - } - else { - - // create contact record - $r = q("INSERT INTO `contact` ( `uid`, `created`, `url`, `addr`, `alias`, `notify`, `poll`, - `name`, `nick`, `photo`, `network`, `rel`, `priority`, - `writable`, `blocked`, `readonly`, `pending` ) - VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ", - intval($uid), - dbesc(datetime_convert()), - dbesc($jp->link), - dbesc(''), - dbesc(''), - dbesc($jp->id), - dbesc('facebook ' . $jp->id), - dbesc($jp->name), - dbesc(($jp->nickname) ? $jp->nickname : strtolower($jp->first_name)), - dbesc('https://graph.facebook.com/' . $jp->id . '/picture'), - dbesc(NETWORK_FACEBOOK), - intval(CONTACT_IS_FRIEND), - intval(1), - intval(1) - ); - } - - $r = q("SELECT * FROM `contact` WHERE `url` = '%s' AND `uid` = %d LIMIT 1", - dbesc($jp->link), - intval($uid) - ); - - if(! count($r)) { - continue; - } - - $contact = $r[0]; - $contact_id = $r[0]['id']; - - require_once("Photo.php"); - - $photos = import_profile_photo($r[0]['photo'],$uid,$contact_id); - - $r = q("UPDATE `contact` SET `photo` = '%s', - `thumb` = '%s', - `micro` = '%s', - `name-date` = '%s', - `uri-date` = '%s', - `avatar-date` = '%s' - WHERE `id` = %d LIMIT 1 - ", - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($contact_id) - ); - - } - } - } -} - -// This is the POST method to the facebook settings page -// Content is posted to Facebook in the function facebook_post_hook() - -function facebook_post(&$a) { - - $uid = local_user(); - if($uid){ - - $value = ((x($_POST,'post_by_default')) ? intval($_POST['post_by_default']) : 0); - set_pconfig($uid,'facebook','post_by_default', $value); - - $no_linking = get_pconfig($uid,'facebook','no_linking'); - - $no_wall = ((x($_POST,'facebook_no_wall')) ? intval($_POST['facebook_no_wall']) : 0); - set_pconfig($uid,'facebook','no_wall',$no_wall); - - $private_wall = ((x($_POST,'facebook_private_wall')) ? intval($_POST['facebook_private_wall']) : 0); - set_pconfig($uid,'facebook','private_wall',$private_wall); - - - $linkvalue = ((x($_POST,'facebook_linking')) ? intval($_POST['facebook_linking']) : 0); - set_pconfig($uid,'facebook','no_linking', (($linkvalue) ? 0 : 1)); - - // FB linkage was allowed but has just been turned off - remove all FB contacts and posts - - if((! intval($no_linking)) && (! intval($linkvalue))) { - $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `network` = '%s' ", - intval($uid), - dbesc(NETWORK_FACEBOOK) - ); - if(count($r)) { - require_once('include/Contact.php'); - foreach($r as $rr) - contact_remove($rr['id']); - } - } - elseif(intval($no_linking) && intval($linkvalue)) { - // FB linkage is now allowed - import stuff. - fb_get_self($uid); - fb_get_friends($uid); - fb_consume_all($uid); - } - - info( t('Settings updated.') . EOL); - } - - return; -} - -// Facebook settings form - -function facebook_content(&$a) { - - if(! local_user()) { - notice( t('Permission denied.') . EOL); - return ''; - } - - if($a->argc > 1 && $a->argv[1] === 'remove') { - del_pconfig(local_user(),'facebook','post'); - info( t('Facebook disabled') . EOL); - } - - if($a->argc > 1 && $a->argv[1] === 'friends') { - fb_get_friends(local_user()); - info( t('Updating contacts') . EOL); - } - - - $fb_installed = get_pconfig(local_user(),'facebook','post'); - - $appid = get_config('facebook','appid'); - - if(! $appid) { - notice( t('Facebook API key is missing.') . EOL); - return ''; - } - - $a->page['htmlhead'] .= '' . "\r\n"; - - $o .= '

' . t('Facebook Connect') . '

'; - - if(! $fb_installed) { - $o .= ''; - } - - if($fb_installed) { - $o .= ''; - - $o .= ''; - - $o .= '
'; - $o .= '
'; - $post_by_default = get_pconfig(local_user(),'facebook','post_by_default'); - $checked = (($post_by_default) ? ' checked="checked" ' : ''); - $o .= '' . ' ' . t('Post to Facebook by default') . EOL; - - $no_linking = get_pconfig(local_user(),'facebook','no_linking'); - $checked = (($no_linking) ? '' : ' checked="checked" '); - $o .= '' . ' ' . t('Link all your Facebook friends and conversations on this website') . EOL ; - - $o .= '

' . t('Facebook conversations consist of your profile wall and your friend stream.'); - $o .= ' ' . t('On this website, your Facebook friend stream is only visible to you.'); - $o .= ' ' . t('The following settings determine the privacy of your Facebook profile wall on this website.') . '

'; - - $private_wall = get_pconfig(local_user(),'facebook','private_wall'); - $checked = (($private_wall) ? ' checked="checked" ' : ''); - $o .= '' . ' ' . t('On this website your Facebook profile wall conversations will only be visible to you') . EOL ; - - - $no_wall = get_pconfig(local_user(),'facebook','no_wall'); - $checked = (($no_wall) ? ' checked="checked" ' : ''); - $o .= '' . ' ' . t('Do not import your Facebook profile wall conversations') . EOL ; - - $o .= '

' . t('If you choose to link conversations and leave both of these boxes unchecked, your Facebook profile wall will be merged with your profile wall on this website and your privacy settings on this website will be used to determine who may see the conversations.') . '

'; - - $o .= '
'; - } - - return $o; -} - - - -function facebook_cron($a,$b) { - - $last = get_config('facebook','last_poll'); - - $poll_interval = intval(get_config('facebook','poll_interval')); - if(! $poll_interval) - $poll_interval = 3600; - - if($last) { - $next = $last + $poll_interval; - if($next > time()) - return; - } - - logger('facebook_cron'); - - - // Find the FB users on this site and randomize in case one of them - // uses an obscene amount of memory. It may kill this queue run - // but hopefully we'll get a few others through on each run. - - $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'facebook' AND `k` = 'post' AND `v` = '1' ORDER BY RAND() "); - if(count($r)) { - foreach($r as $rr) { - if(get_pconfig($rr['uid'],'facebook','no_linking')) - continue; - // check for new friends once a day - $last_friend_check = get_pconfig($rr['uid'],'facebook','friend_check'); - if($last_friend_check) - $next_friend_check = $last_friend_check + 86400; - if($next_friend_check <= time()) { - fb_get_friends($rr['uid']); - set_pconfig($rr['uid'],'facebook','friend_check',time()); - } - fb_consume_all($rr['uid']); - } - } - - set_config('facebook','last_poll', time()); - -} - - - -function facebook_plugin_settings(&$a,&$b) { - - $b .= '
'; - $b .= '

' . t('Facebook') . '

'; - $b .= '' . t('Facebook Connector Settings') . '
'; - $b .= '
'; - -} - -function facebook_jot_nets(&$a,&$b) { - if(! local_user()) - return; - - $fb_post = get_pconfig(local_user(),'facebook','post'); - if(intval($fb_post) == 1) { - $fb_defpost = get_pconfig(local_user(),'facebook','post_by_default'); - $selected = ((intval($fb_defpost) == 1) ? ' checked="checked" ' : ''); - $b .= '
' - . t('Post to Facebook') . '
'; - } -} - - -function facebook_post_hook(&$a,&$b) { - - /** - * Post to Facebook stream - */ - - require_once('include/group.php'); - - logger('Facebook post'); - - $reply = false; - $likes = false; - - if((local_user()) && (local_user() == $b['uid'])) { - - // Facebook is not considered a private network - if($b['prvnets'] && $b['private']) - return; - - $linking = ((get_pconfig(local_user(),'facebook','no_linking')) ? 0 : 1); - - if(($b['parent']) && ($linking)) { - $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($b['parent']), - intval(local_user()) - ); - if(count($r) && substr($r[0]['uri'],0,4) === 'fb::') - $reply = substr($r[0]['uri'],4); - elseif(count($r) && substr($r[0]['extid'],0,4) === 'fb::') - $reply = substr($r[0]['extid'],4); - else - return; - logger('facebook reply id=' . $reply); - } - - if($b['private'] && $reply === false) { - $allow_people = expand_acl($b['allow_cid']); - $allow_groups = expand_groups(expand_acl($b['allow_gid'])); - $deny_people = expand_acl($b['deny_cid']); - $deny_groups = expand_groups(expand_acl($b['deny_gid'])); - - $recipients = array_unique(array_merge($allow_people,$allow_groups)); - $deny = array_unique(array_merge($deny_people,$deny_groups)); - - $allow_str = dbesc(implode(', ',$recipients)); - if($allow_str) { - $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( $allow_str ) AND `network` = 'face'"); - $allow_arr = array(); - if(count($r)) - foreach($r as $rr) - $allow_arr[] = $rr['notify']; - } - - $deny_str = dbesc(implode(', ',$deny)); - if($deny_str) { - $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( $deny_str ) AND `network` = 'face'"); - $deny_arr = array(); - if(count($r)) - foreach($r as $rr) - $deny_arr[] = $rr['notify']; - } - - if(count($deny_arr) && (! count($allow_arr))) { - - // One or more FB folks were denied access but nobody on FB was specifically allowed access. - // This might cause the post to be open to public on Facebook, but only to selected members - // on another network. Since this could potentially leak a post to somebody who was denied, - // we will skip posting it to Facebook with a slightly vague but relevant message that will - // hopefully lead somebody to this code comment for a better explanation of what went wrong. - - notice( t('Post to Facebook cancelled because of multi-network access permission conflict.') . EOL); - return; - } - - - // if it's a private message but no Facebook members are allowed or denied, skip Facebook post - - if((! count($allow_arr)) && (! count($deny_arr))) - return; - } - - if($b['verb'] == ACTIVITY_LIKE) - $likes = true; - - - $appid = get_config('facebook', 'appid' ); - $secret = get_config('facebook', 'appsecret' ); - - if($appid && $secret) { - - logger('facebook: have appid+secret'); - - $fb_post = intval(get_pconfig(local_user(),'facebook','post')); - $fb_enable = (($fb_post && x($_POST,'facebook_enable')) ? intval($_POST['facebook_enable']) : 0); - $fb_token = get_pconfig(local_user(),'facebook','access_token'); - - // if API is used, default to the chosen settings - if($_POST['api_source'] && intval(get_pconfig(local_user(),'facebook','post_by_default'))) - $fb_enable = 1; - - - - - logger('facebook: $fb_post: ' . $fb_post . ' $fb_enable: ' . $fb_enable . ' $fb_token: ' . $fb_token,LOGGER_DEBUG); - - // post to facebook if it's a public post and we've ticked the 'post to Facebook' box, - // or it's a private message with facebook participants - // or it's a reply or likes action to an existing facebook post - - if($fb_post && $fb_token && ($fb_enable || $b['private'] || $reply)) { - logger('facebook: able to post'); - require_once('library/facebook.php'); - require_once('include/bbcode.php'); - - $msg = $b['body']; - - logger('Facebook post: original msg=' . $msg, LOGGER_DATA); - - // make links readable before we strip the code - - // unless it's a dislike - just send the text as a comment - - if($b['verb'] == ACTIVITY_DISLIKE) - $msg = trim(strip_tags(bbcode($msg))); - - $search_str = $a->get_baseurl() . '/search'; - - if(preg_match("/\[url=(.*?)\](.*?)\[\/url\]/is",$msg,$matches)) { - - // don't use hashtags for message link - - if(strpos($matches[2],$search_str) === false) { - $link = $matches[1]; - if(substr($matches[2],0,5) != '[img]') - $linkname = $matches[2]; - } - } - - $msg = preg_replace("/\[url=(.*?)\](.*?)\[\/url\]/is",'$2 $1',$msg); - - if(preg_match("/\[img\](.*?)\[\/img\]/is",$msg,$matches)) - $image = $matches[1]; - - $msg = preg_replace("/\[img\](.*?)\[\/img\]/is", t('Image: ') . '$1', $msg); - - if((strpos($link,z_root()) !== false) && (! $image)) - $image = $a->get_baseurl() . '/images/friendika-64.jpg'; - - $msg = trim(strip_tags(bbcode($msg))); - $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8'); - - // add any attachments as text urls - - $arr = explode(',',$b['attach']); - - if(count($arr)) { - $msg .= "\n"; - foreach($arr as $r) { - $matches = false; - $cnt = preg_match('|\[attach\]href=\"(.*?)\" size=\"(.*?)\" type=\"(.*?)\" title=\"(.*?)\"\[\/attach\]|',$r,$matches); - if($cnt) { - $msg .= $matches[1]; - } - } - } - - if (strlen($msg) > FACEBOOK_MAXPOSTLEN) { - $shortlink = ""; - require_once('library/slinky.php'); - - $display_url = $a->get_baseurl() . '/display/' . $a->user['nickname'] . '/' . $b['id']; - $slinky = new Slinky( $display_url ); - // setup a cascade of shortening services - // try to get a short link from these services - // in the order ur1.ca, trim, id.gd, tinyurl - $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) ); - $shortlink = $slinky->short(); - // the new message will be shortened such that "... $shortlink" - // will fit into the character limit - $msg = substr($msg, 0, FACEBOOK_MAXPOSTLEN - strlen($shortlink) - 4); - $msg .= '... ' . $shortlink; - } - if(! strlen($msg)) - return; - - logger('Facebook post: msg=' . $msg, LOGGER_DATA); - - if($likes) { - $postvars = array('access_token' => $fb_token); - } - else { - $postvars = array( - 'access_token' => $fb_token, - 'message' => $msg - ); - if(isset($image)) - $postvars['picture'] = $image; - if(isset($link)) - $postvars['link'] = $link; - if(isset($linkname)) - $postvars['name'] = $linkname; - } - - if(($b['private']) && (! $b['parent'])) { - $postvars['privacy'] = '{"value": "CUSTOM", "friends": "SOME_FRIENDS"'; - if(count($allow_arr)) - $postvars['privacy'] .= ',"allow": "' . implode(',',$allow_arr) . '"'; - if(count($deny_arr)) - $postvars['privacy'] .= ',"deny": "' . implode(',',$deny_arr) . '"'; - $postvars['privacy'] .= '}'; - - } - - if($reply) { - $url = 'https://graph.facebook.com/' . $reply . '/' . (($likes) ? 'likes' : 'comments'); - } - else { - $url = 'https://graph.facebook.com/me/feed'; - if($b['plink']) - $postvars['actions'] = '{"name": "' . t('View on Friendika') . '", "link": "' . $b['plink'] . '"}'; - } - - logger('facebook: post to ' . $url); - logger('facebook: postvars: ' . print_r($postvars,true)); - - // "test_mode" prevents anything from actually being posted. - // Otherwise, let's do it. - - if(! get_config('facebook','test_mode')) { - $x = post_url($url, $postvars); - - $retj = json_decode($x); - if($retj->id) { - q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1", - dbesc('fb::' . $retj->id), - intval($b['id']) - ); - } - else { - if(! $likes) { - $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $postvars)); - q("INSERT INTO `queue` ( `network`, `cid`, `created`, `last`, `content`) - VALUES ( '%s', %d, '%s', '%s', '%s') ", - dbesc(NETWORK_FACEBOOK), - intval($a->contact), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc($s) - ); - - notice( t('Facebook post failed. Queued for retry.') . EOL); - } - } - - logger('Facebook post returns: ' . $x, LOGGER_DEBUG); - } - } - } - } -} - - -function fb_queue_hook(&$a,&$b) { - - $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'", - dbesc(NETWORK_FACEBOOK) - ); - if(! count($qi)) - return; - - require_once('include/queue_fn.php'); - - foreach($qi as $x) { - if($x['network'] !== NETWORK_FACEBOOK) - continue; - - logger('facebook_queue: run'); - - $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` - WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1", - intval($x['cid']) - ); - if(! count($r)) - continue; - - $user = $r[0]; - - $appid = get_config('facebook', 'appid' ); - $secret = get_config('facebook', 'appsecret' ); - - if($appid && $secret) { - $fb_post = intval(get_pconfig($user['uid'],'facebook','post')); - $fb_token = get_pconfig($user['uid'],'facebook','access_token'); - - if($fb_post && $fb_token) { - logger('facebook_queue: able to post'); - require_once('library/facebook.php'); - - $z = unserialize($x['content']); - $item = $z['item']; - $j = post_url($z['url'],$z['post']); - - $retj = json_decode($j); - if($retj->id) { - q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1", - dbesc('fb::' . $retj->id), - intval($item) - ); - logger('facebook_queue: success: ' . $j); - remove_queue_item($x['id']); - } - else { - logger('facebook_queue: failed: ' . $j); - update_queue_time($x['id']); - } - } - } - } -} - -function fb_consume_all($uid) { - - require_once('include/items.php'); - - $access_token = get_pconfig($uid,'facebook','access_token'); - if(! $access_token) - return; - - if(! get_pconfig($uid,'facebook','no_wall')) { - $private_wall = intval(get_pconfig($uid,'facebook','private_wall')); - $s = fetch_url('https://graph.facebook.com/me/feed?access_token=' . $access_token); - if($s) { - $j = json_decode($s); - logger('fb_consume_stream: wall: ' . print_r($j,true), LOGGER_DATA); - fb_consume_stream($uid,$j,($private_wall) ? false : true); - } - } - $s = fetch_url('https://graph.facebook.com/me/home?access_token=' . $access_token); - if($s) { - $j = json_decode($s); - logger('fb_consume_stream: feed: ' . print_r($j,true), LOGGER_DATA); - fb_consume_stream($uid,$j,false); - } - -} - -function fb_consume_stream($uid,$j,$wall = false) { - - $a = get_app(); - - - $user = q("SELECT `nickname`, `blockwall` FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", - intval($uid) - ); - if(! count($user)) - return; - - $my_local_url = $a->get_baseurl() . '/profile/' . $user[0]['nickname']; - - $no_linking = get_pconfig($uid,'facebook','no_linking'); - if($no_linking) - return; - - $self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", - intval($uid) - ); - - - $self_id = get_pconfig($uid,'facebook','self_id'); - if(! count($j->data) || (! strlen($self_id))) - return; - - foreach($j->data as $entry) { - logger('fb_consume: entry: ' . print_r($entry,true), LOGGER_DATA); - $datarray = array(); - - $r = q("SELECT * FROM `item` WHERE ( `uri` = '%s' OR `extid` = '%s') AND `uid` = %d LIMIT 1", - dbesc('fb::' . $entry->id), - dbesc('fb::' . $entry->id), - intval($uid) - ); - if(count($r)) { - $post_exists = true; - $orig_post = $r[0]; - $top_item = $r[0]['id']; - } - else { - $post_exists = false; - $orig_post = null; - } - - if(! $orig_post) { - $datarray['gravity'] = 0; - $datarray['uid'] = $uid; - $datarray['wall'] = (($wall) ? 1 : 0); - $datarray['uri'] = $datarray['parent-uri'] = 'fb::' . $entry->id; - $from = $entry->from; - if($from->id == $self_id) - $datarray['contact-id'] = $self[0]['id']; - else { - $r = q("SELECT * FROM `contact` WHERE `notify` = '%s' AND `uid` = %d AND `blocked` = 0 AND `readonly` = 0 LIMIT 1", - dbesc($from->id), - intval($uid) - ); - if(count($r)) - $datarray['contact-id'] = $r[0]['id']; - } - - // don't store post if we don't have a contact - - if(! x($datarray,'contact-id')) { - logger('no contact: post ignored'); - continue; - } - - $datarray['verb'] = ACTIVITY_POST; - if($wall) { - $datarray['owner-name'] = $self[0]['name']; - $datarray['owner-link'] = $self[0]['url']; - $datarray['owner-avatar'] = $self[0]['thumb']; - } - if(isset($entry->application) && isset($entry->application->name) && strlen($entry->application->name)) - $datarray['app'] = strip_tags($entry->application->name); - else - $datarray['app'] = 'facebook'; - $datarray['author-name'] = $from->name; - $datarray['author-link'] = 'http://facebook.com/profile.php?id=' . $from->id; - $datarray['author-avatar'] = 'https://graph.facebook.com/' . $from->id . '/picture'; - $datarray['plink'] = $datarray['author-link'] . '&v=wall&story_fbid=' . substr($entry->id,strpos($entry->id,'_') + 1); - - $datarray['body'] = $entry->message; - if($entry->picture) - $datarray['body'] .= "\n\n" . '[img]' . $entry->picture . '[/img]'; - if($entry->link) - $datarray['body'] .= "\n" . linkify($entry->link); - if($entry->name) - $datarray['body'] .= "\n" . $entry->name; - if($entry->caption) - $datarray['body'] .= "\n" . $entry->caption; - if($entry->description) - $datarray['body'] .= "\n" . $entry->description; - $datarray['created'] = datetime_convert('UTC','UTC',$entry->created_time); - $datarray['edited'] = datetime_convert('UTC','UTC',$entry->updated_time); - - // If the entry has a privacy policy, we cannot assume who can or cannot see it, - // as the identities are from a foreign system. Mark it as private to the owner. - - if($entry->privacy && $entry->privacy->value !== 'EVERYONE') { - $datarray['private'] = 1; - $datarray['allow_cid'] = '<' . $uid . '>'; - } - - $top_item = item_store($datarray); - $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", - intval($top_item), - intval($uid) - ); - if(count($r)) { - $orig_post = $r[0]; - logger('fb: new top level item posted'); - } - } - - if(isset($entry->likes) && isset($entry->likes->data)) - $likers = $entry->likes->data; - else - $likers = null; - - if(isset($entry->comments) && isset($entry->comments->data)) - $comments = $entry->comments->data; - else - $comments = null; - - if(is_array($likers)) { - foreach($likers as $likes) { - - if(! $orig_post) - continue; - - // If we posted the like locally, it will be found with our url, not the FB url. - - $second_url = (($likes->id == $self_id) ? $self[0]['url'] : 'http://facebook.com/profile.php?id=' . $likes->id); - - $r = q("SELECT * FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `verb` = '%s' - AND ( `author-link` = '%s' OR `author-link` = '%s' ) LIMIT 1", - dbesc($orig_post['uri']), - intval($uid), - dbesc(ACTIVITY_LIKE), - dbesc('http://facebook.com/profile.php?id=' . $likes->id), - dbesc($second_url) - ); - - if(count($r)) - continue; - - $likedata = array(); - $likedata['parent'] = $top_item; - $likedata['verb'] = ACTIVITY_LIKE; - $likedata['gravity'] = 3; - $likedata['uid'] = $uid; - $likedata['wall'] = (($wall) ? 1 : 0); - $likedata['uri'] = item_new_uri($a->get_baseurl(), $uid); - $likedata['parent-uri'] = $orig_post['uri']; - if($likes->id == $self_id) - $likedata['contact-id'] = $self[0]['id']; - else { - $r = q("SELECT * FROM `contact` WHERE `notify` = '%s' AND `uid` = %d AND `blocked` = 0 AND `readonly` = 0 LIMIT 1", - dbesc($likes->id), - intval($uid) - ); - if(count($r)) - $likedata['contact-id'] = $r[0]['id']; - } - if(! x($likedata,'contact-id')) - $likedata['contact-id'] = $orig_post['contact-id']; - - $likedata['app'] = 'facebook'; - $likedata['verb'] = ACTIVITY_LIKE; - $likedata['author-name'] = $likes->name; - $likedata['author-link'] = 'http://facebook.com/profile.php?id=' . $likes->id; - $likedata['author-avatar'] = 'https://graph.facebook.com/' . $likes->id . '/picture'; - - $author = '[url=' . $likedata['author-link'] . ']' . $likedata['author-name'] . '[/url]'; - $objauthor = '[url=' . $orig_post['author-link'] . ']' . $orig_post['author-name'] . '[/url]'; - $post_type = t('status'); - $plink = '[url=' . $orig_post['plink'] . ']' . $post_type . '[/url]'; - $likedata['object-type'] = ACTIVITY_OBJ_NOTE; - - $likedata['body'] = sprintf( t('%1$s likes %2$s\'s %3$s'), $author, $objauthor, $plink); - $likedata['object'] = '' . ACTIVITY_OBJ_NOTE . '1' . - '' . $orig_post['uri'] . '' . xmlify('') . '' . $orig_post['title'] . '' . $orig_post['body'] . ''; - - $item = item_store($likedata); - } - } - if(is_array($comments)) { - foreach($comments as $cmnt) { - - if(! $orig_post) - continue; - - $r = q("SELECT * FROM `item` WHERE `uid` = %d AND ( `uri` = '%s' OR `extid` = '%s' ) LIMIT 1", - intval($uid), - dbesc('fb::' . $cmnt->id), - dbesc('fb::' . $cmnt->id) - ); - if(count($r)) - continue; - - $cmntdata = array(); - $cmntdata['parent'] = $top_item; - $cmntdata['verb'] = ACTIVITY_POST; - $cmntdata['gravity'] = 6; - $cmntdata['uid'] = $uid; - $cmntdata['wall'] = (($wall) ? 1 : 0); - $cmntdata['uri'] = 'fb::' . $cmnt->id; - $cmntdata['parent-uri'] = $orig_post['uri']; - if($cmnt->from->id == $self_id) { - $cmntdata['contact-id'] = $self[0]['id']; - } - else { - $r = q("SELECT * FROM `contact` WHERE `notify` = '%s' AND `uid` = %d LIMIT 1", - dbesc($cmnt->from->id), - intval($uid) - ); - if(count($r)) { - $cmntdata['contact-id'] = $r[0]['id']; - if($r[0]['blocked'] || $r[0]['readonly']) - continue; - } - } - if(! x($cmntdata,'contact-id')) - $cmntdata['contact-id'] = $orig_post['contact-id']; - - $cmntdata['app'] = 'facebook'; - $cmntdata['created'] = datetime_convert('UTC','UTC',$cmnt->created_time); - $cmntdata['edited'] = datetime_convert('UTC','UTC',$cmnt->created_time); - $cmntdata['verb'] = ACTIVITY_POST; - $cmntdata['author-name'] = $cmnt->from->name; - $cmntdata['author-link'] = 'http://facebook.com/profile.php?id=' . $cmnt->from->id; - $cmntdata['author-avatar'] = 'https://graph.facebook.com/' . $cmnt->from->id . '/picture'; - $cmntdata['body'] = $cmnt->message; - $item = item_store($cmntdata); - } - } - } -} - diff --git a/addon/fortunate/fortunate.css b/addon/fortunate/fortunate.css deleted file mode 100644 index 61813b7d7..000000000 --- a/addon/fortunate/fortunate.css +++ /dev/null @@ -1,7 +0,0 @@ -.fortunate { - margin-top: 25px; - margin-left: 100px; - margin-bottom: 25px; - color: #000088; - font-size: 14px; -} \ No newline at end of file diff --git a/addon/fortunate/fortunate.php b/addon/fortunate/fortunate.php deleted file mode 100644 index 5a6302e58..000000000 --- a/addon/fortunate/fortunate.php +++ /dev/null @@ -1,27 +0,0 @@ - - */ - - -function fortunate_install() { - register_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch'); -} - -function fortunate_uninstall() { - unregister_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch'); -} - - -function fortunate_fetch($a,&$b) { - - $a->page['htmlhead'] .= '' . "\r\n"; - - $s = fetch_url('http://fortunemod.com/cookie.php?numlines=2&equal=1&rand=' . mt_rand()); - $b .= '
' . $s . '
'; -} - diff --git a/addon/impressum/README b/addon/impressum/README deleted file mode 100644 index 8e4255bd1..000000000 --- a/addon/impressum/README +++ /dev/null @@ -1,27 +0,0 @@ -Impressum Plugin for Friendika - -Author: Tobias Diekershoff - tobias.diekershoff@gmx.net - -License: 3-clause BSD license (same as Friendika) - -About - This plugin adds an Impressum block to the /friendika page with informations - about the page operator/owner and how to contact you in case of any questions. - - In the notes and postal fields you can use HTML tags for formatting. - -Configuration: - For configuration you can set the following variables in the .htconfig file - * $a->config['impressum']['owner'] this is the Name of the Operator - * $a->config['impressum']['ownerprofile'] this is an optional Friendika account - where the above owner name will link to - * $a->config['impressum']['email'] a contact email address (optional) - will be displayed slightly obfuscated - as name(at)example(dot)com - * $a->config['impressum']['postal'] should contain a postal address where - you can be reached at (optional) - * $a->config['impressum']['notes'] additional informations that should - be displayed in the Impressum block - - diff --git a/addon/impressum/admin.tpl b/addon/impressum/admin.tpl deleted file mode 100644 index cfba8df76..000000000 --- a/addon/impressum/admin.tpl +++ /dev/null @@ -1,6 +0,0 @@ -{{ inc field_input.tpl with $field=$owner }}{{ endinc }} -{{ inc field_input.tpl with $field=$ownerprofile }}{{ endinc }} -{{ inc field_input.tpl with $field=$postal }}{{ endinc }} -{{ inc field_input.tpl with $field=$notes }}{{ endinc }} -{{ inc field_input.tpl with $field=$email }}{{ endinc }} -
diff --git a/addon/impressum/impressum.php b/addon/impressum/impressum.php deleted file mode 100644 index b760c7e0d..000000000 --- a/addon/impressum/impressum.php +++ /dev/null @@ -1,76 +0,0 @@ - - * License: 3-clause BSD license - */ - -function impressum_install() { - register_hook('about_hook', 'addon/impressum/impressum.php', 'impressum_show'); - logger("installed impressum plugin"); -} - -function impressum_uninstall() { - unregister_hook('about_hook', 'addon/impressum/impressum.php', 'impressum_show'); - logger("uninstalled impressum plugin"); -} -function obfuscate_email ($s) { - $s = str_replace('@','(at)',$s); - $s = str_replace('.','(dot)',$s); - return $s; -} -function impressum_show($a,&$b) { - $b .= '

'.t('Impressum').'

'; - $owner = get_config('impressum', 'owner'); - $owner_profile = get_config('impressum','ownerprofile'); - $postal = get_config('impressum', 'postal'); - $notes = get_config('impressum', 'notes'); - $email = obfuscate_email( get_config('impressum','email') ); - if (strlen($owner)) { - if (strlen($owner_profile)) { - $tmp = ''.$owner.''; - } else { - $tmp = $owner; - } - if (strlen($email)) { - $b .= '

'.t('Site Owner').': '. $tmp .'
'.t('Email Address').': '.$email.'

'; - } else { - $b .= '

'.t('Site Owner').': '. $tmp .'

'; - } - if (strlen($postal)) { - $b .= '

'.t('Postal Address').'
'. $postal .'

'; - } - if (strlen($notes)) { - $b .= '

'.$notes.'

'; - } - } else { - $b .= '

'.t('The impressum addon needs to be configured!
Please add at least the owner variable to your config file. For other variables please refer to the README file of the addon.').'

'; - } -} - -function impressum_plugin_admin_post (&$a) { - $owner = ((x($_POST, 'owner')) ? notags(trim($_POST['owner'])) : ''); - $ownerprofile = ((x($_POST, 'ownerprofile')) ? notags(trim($_POST['ownerprofile'])) : ''); - $postal = ((x($_POST, 'postal')) ? (trim($_POST['postal'])) : ''); - $notes = ((x($_POST, 'notes')) ? (trim($_POST['notes'])) : ''); - $email = ((x($_POST, 'email')) ? notags(trim($_POST['email'])) : ''); - set_config('impressum','owner',$owner); - set_config('impressum','ownerprofile',$ownerprofile); - set_config('impressum','postal',$postal); - set_config('impressum','email',$email); - set_config('impressum','notes',$notes); - info( t('Settings updated.'). EOL ); -} -function impressum_plugin_admin (&$a, &$o) { - $t = file_get_contents( dirname(__file__). "/admin.tpl" ); - $o = replace_macros($t, array( - '$submit' => t('Submit'), - '$owner' => array('owner', t('Site Owner'), get_config('impressum','owner'), ''), - '$ownerprofile' => array('ownerprofile', t('Site Owners Profile'), get_config('impressum','ownerprofile'), ''), - '$postal' => array('postal', t('Postal Address'), get_config('impressum','postal'), ''), - '$notes' => array('notes', t('Notes'), get_config('impressum','notes'), ''), - '$email' => array('email', t('Email Address'), get_config('impressum','email'), ''), - )); -} diff --git a/addon/js_upload/file-uploader/client/demo.htm b/addon/js_upload/file-uploader/client/demo.htm deleted file mode 100644 index 2a0cd6d30..000000000 --- a/addon/js_upload/file-uploader/client/demo.htm +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - -

Back to project page

- -

To upload a file, click on the button below. Drag-and-drop is supported in FF, Chrome.

-

Progress-bar is supported in FF3.6+, Chrome6+, Safari4+

- -
- -
- - - - - \ No newline at end of file diff --git a/addon/js_upload/file-uploader/client/do-nothing.htm b/addon/js_upload/file-uploader/client/do-nothing.htm deleted file mode 100644 index 0da19059d..000000000 --- a/addon/js_upload/file-uploader/client/do-nothing.htm +++ /dev/null @@ -1 +0,0 @@ -{success:true} diff --git a/addon/js_upload/file-uploader/client/fileuploader.css b/addon/js_upload/file-uploader/client/fileuploader.css deleted file mode 100644 index 0e3f111a9..000000000 --- a/addon/js_upload/file-uploader/client/fileuploader.css +++ /dev/null @@ -1,31 +0,0 @@ -.qq-uploader { position:relative; width: 100%;} - -.qq-upload-button { - display:block; /* or inline-block */ - width: 105px; padding: 7px 0; text-align:center; - background:#880000; border-bottom:1px solid #ddd;color:#fff; -} -.qq-upload-button-hover {background:#cc0000;} -.qq-upload-button-focus {outline:1px dotted black;} - -.qq-upload-drop-area { - position:absolute; top:0; left:0; width:100%; height:100%; min-height: 70px; z-index:2; - background:#FF9797; text-align:center; -} -.qq-upload-drop-area span { - display:block; position:absolute; top: 50%; width:100%; margin-top:-8px; font-size:16px; -} -.qq-upload-drop-area-active {background:#FF7171;} - -.qq-upload-list {margin:15px 35px; padding:0; list-style:disc;} -.qq-upload-list li { margin:0; padding:0; line-height:15px; font-size:12px;} -.qq-upload-file, .qq-upload-spinner, .qq-upload-size, .qq-upload-cancel, .qq-upload-failed-text { - margin-right: 7px; -} - -.qq-upload-file {} -.qq-upload-spinner {display:inline-block; background: url("loading.gif"); width:15px; height:15px; vertical-align:text-bottom;} -.qq-upload-size,.qq-upload-cancel {font-size:11px;} - -.qq-upload-failed-text {display:none;} -.qq-upload-fail .qq-upload-failed-text {display:inline;} \ No newline at end of file diff --git a/addon/js_upload/file-uploader/client/fileuploader.js b/addon/js_upload/file-uploader/client/fileuploader.js deleted file mode 100644 index 89c09ebf5..000000000 --- a/addon/js_upload/file-uploader/client/fileuploader.js +++ /dev/null @@ -1,1247 +0,0 @@ -/** - * http://github.com/valums/file-uploader - * - * Multiple file upload component with progress-bar, drag-and-drop. - * © 2010 Andrew Valums ( andrew(at)valums.com ) - * - * Licensed under GNU GPL 2 or later, see license.txt. - */ - -// -// Helper functions -// - -var qq = qq || {}; - -/** - * Adds all missing properties from second obj to first obj - */ -qq.extend = function(first, second){ - for (var prop in second){ - first[prop] = second[prop]; - } -}; - -/** - * Searches for a given element in the array, returns -1 if it is not present. - * @param {Number} [from] The index at which to begin the search - */ -qq.indexOf = function(arr, elt, from){ - if (arr.indexOf) return arr.indexOf(elt, from); - - from = from || 0; - var len = arr.length; - - if (from < 0) from += len; - - for (; from < len; from++){ - if (from in arr && arr[from] === elt){ - return from; - } - } - return -1; -}; - -qq.getUniqueId = (function(){ - var id = 0; - return function(){ return id++; }; -})(); - -// -// Events - -qq.attach = function(element, type, fn){ - if (element.addEventListener){ - element.addEventListener(type, fn, false); - } else if (element.attachEvent){ - element.attachEvent('on' + type, fn); - } -}; -qq.detach = function(element, type, fn){ - if (element.removeEventListener){ - element.removeEventListener(type, fn, false); - } else if (element.attachEvent){ - element.detachEvent('on' + type, fn); - } -}; - -qq.preventDefault = function(e){ - if (e.preventDefault){ - e.preventDefault(); - } else{ - e.returnValue = false; - } -}; - -// -// Node manipulations - -/** - * Insert node a before node b. - */ -qq.insertBefore = function(a, b){ - b.parentNode.insertBefore(a, b); -}; -qq.remove = function(element){ - element.parentNode.removeChild(element); -}; - -qq.contains = function(parent, descendant){ - // compareposition returns false in this case - if (parent == descendant) return true; - - if (parent.contains){ - return parent.contains(descendant); - } else { - return !!(descendant.compareDocumentPosition(parent) & 8); - } -}; - -/** - * Creates and returns element from html string - * Uses innerHTML to create an element - */ -qq.toElement = (function(){ - var div = document.createElement('div'); - return function(html){ - div.innerHTML = html; - var element = div.firstChild; - div.removeChild(element); - return element; - }; -})(); - -// -// Node properties and attributes - -/** - * Sets styles for an element. - * Fixes opacity in IE6-8. - */ -qq.css = function(element, styles){ - if (styles.opacity != null){ - if (typeof element.style.opacity != 'string' && typeof(element.filters) != 'undefined'){ - styles.filter = 'alpha(opacity=' + Math.round(100 * styles.opacity) + ')'; - } - } - qq.extend(element.style, styles); -}; -qq.hasClass = function(element, name){ - var re = new RegExp('(^| )' + name + '( |$)'); - return re.test(element.className); -}; -qq.addClass = function(element, name){ - if (!qq.hasClass(element, name)){ - element.className += ' ' + name; - } -}; -qq.removeClass = function(element, name){ - var re = new RegExp('(^| )' + name + '( |$)'); - element.className = element.className.replace(re, ' ').replace(/^\s+|\s+$/g, ""); -}; -qq.setText = function(element, text){ - element.innerText = text; - element.textContent = text; -}; - -// -// Selecting elements - -qq.children = function(element){ - var children = [], - child = element.firstChild; - - while (child){ - if (child.nodeType == 1){ - children.push(child); - } - child = child.nextSibling; - } - - return children; -}; - -qq.getByClass = function(element, className){ - if (element.querySelectorAll){ - return element.querySelectorAll('.' + className); - } - - var result = []; - var candidates = element.getElementsByTagName("*"); - var len = candidates.length; - - for (var i = 0; i < len; i++){ - if (qq.hasClass(candidates[i], className)){ - result.push(candidates[i]); - } - } - return result; -}; - -/** - * obj2url() takes a json-object as argument and generates - * a querystring. pretty much like jQuery.param() - * - * how to use: - * - * `qq.obj2url({a:'b',c:'d'},'http://any.url/upload?otherParam=value');` - * - * will result in: - * - * `http://any.url/upload?otherParam=value&a=b&c=d` - * - * @param Object JSON-Object - * @param String current querystring-part - * @return String encoded querystring - */ -qq.obj2url = function(obj, temp, prefixDone){ - var uristrings = [], - prefix = '&', - add = function(nextObj, i){ - var nextTemp = temp - ? (/\[\]$/.test(temp)) // prevent double-encoding - ? temp - : temp+'['+i+']' - : i; - if ((nextTemp != 'undefined') && (i != 'undefined')) { - uristrings.push( - (typeof nextObj === 'object') - ? qq.obj2url(nextObj, nextTemp, true) - : (Object.prototype.toString.call(nextObj) === '[object Function]') - ? encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj()) - : encodeURIComponent(nextTemp) + '=' + encodeURIComponent(nextObj) - ); - } - }; - - if (!prefixDone && temp) { - prefix = (/\?/.test(temp)) ? (/\?$/.test(temp)) ? '' : '&' : '?'; - uristrings.push(temp); - uristrings.push(qq.obj2url(obj)); - } else if ((Object.prototype.toString.call(obj) === '[object Array]') && (typeof obj != 'undefined') ) { - // we wont use a for-in-loop on an array (performance) - for (var i = 0, len = obj.length; i < len; ++i){ - add(obj[i], i); - } - } else if ((typeof obj != 'undefined') && (obj !== null) && (typeof obj === "object")){ - // for anything else but a scalar, we will use for-in-loop - for (var i in obj){ - add(obj[i], i); - } - } else { - uristrings.push(encodeURIComponent(temp) + '=' + encodeURIComponent(obj)); - } - - return uristrings.join(prefix) - .replace(/^&/, '') - .replace(/%20/g, '+'); -}; - -// -// -// Uploader Classes -// -// - -var qq = qq || {}; - -/** - * Creates upload button, validates upload, but doesn't create file list or dd. - */ -qq.FileUploaderBasic = function(o){ - this._options = { - // set to true to see the server response - debug: false, - action: '/server/upload', - params: {}, - button: null, - multiple: true, - maxConnections: 3, - // validation - allowedExtensions: [], - sizeLimit: 0, - minSizeLimit: 0, - // events - // return false to cancel submit - onSubmit: function(id, fileName){}, - onProgress: function(id, fileName, loaded, total){}, - onComplete: function(id, fileName, responseJSON){}, - onCancel: function(id, fileName){}, - // messages - messages: { - typeError: "{file} has invalid extension. Only {extensions} are allowed.", - sizeError: "{file} is too large, maximum file size is {sizeLimit}.", - minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.", - emptyError: "{file} is empty, please select files again without it.", - onLeave: "The files are being uploaded, if you leave now the upload will be cancelled." - }, - showMessage: function(message){ - alert(message); - } - }; - qq.extend(this._options, o); - - // number of files being uploaded - this._filesInProgress = 0; - this._handler = this._createUploadHandler(); - - if (this._options.button){ - this._button = this._createUploadButton(this._options.button); - } - - this._preventLeaveInProgress(); -}; - -qq.FileUploaderBasic.prototype = { - setParams: function(params){ - this._options.params = params; - }, - getInProgress: function(){ - return this._filesInProgress; - }, - _createUploadButton: function(element){ - var self = this; - - return new qq.UploadButton({ - element: element, - multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(), - onChange: function(input){ - self._onInputChange(input); - } - }); - }, - _createUploadHandler: function(){ - var self = this, - handlerClass; - - if(qq.UploadHandlerXhr.isSupported()){ - handlerClass = 'UploadHandlerXhr'; - } else { - handlerClass = 'UploadHandlerForm'; - } - - var handler = new qq[handlerClass]({ - debug: this._options.debug, - action: this._options.action, - maxConnections: this._options.maxConnections, - onProgress: function(id, fileName, loaded, total){ - self._onProgress(id, fileName, loaded, total); - self._options.onProgress(id, fileName, loaded, total); - }, - onComplete: function(id, fileName, result){ - self._onComplete(id, fileName, result); - self._options.onComplete(id, fileName, result); - }, - onCancel: function(id, fileName){ - self._onCancel(id, fileName); - self._options.onCancel(id, fileName); - } - }); - - return handler; - }, - _preventLeaveInProgress: function(){ - var self = this; - - qq.attach(window, 'beforeunload', function(e){ - if (!self._filesInProgress){return;} - - var e = e || window.event; - // for ie, ff - e.returnValue = self._options.messages.onLeave; - // for webkit - return self._options.messages.onLeave; - }); - }, - _onSubmit: function(id, fileName){ - this._filesInProgress++; - }, - _onProgress: function(id, fileName, loaded, total){ - }, - _onComplete: function(id, fileName, result){ - this._filesInProgress--; - if (result.error){ - this._options.showMessage(result.error); - } - }, - _onCancel: function(id, fileName){ - this._filesInProgress--; - }, - _onInputChange: function(input){ - if (this._handler instanceof qq.UploadHandlerXhr){ - this._uploadFileList(input.files); - } else { - if (this._validateFile(input)){ - this._uploadFile(input); - } - } - this._button.reset(); - }, - _uploadFileList: function(files){ - for (var i=0; i this._options.sizeLimit){ - this._error('sizeError', name); - return false; - - } else if (size && size < this._options.minSizeLimit){ - this._error('minSizeError', name); - return false; - } - - return true; - }, - _error: function(code, fileName){ - var message = this._options.messages[code]; - function r(name, replacement){ message = message.replace(name, replacement); } - - r('{file}', this._formatFileName(fileName)); - r('{extensions}', this._options.allowedExtensions.join(', ')); - r('{sizeLimit}', this._formatSize(this._options.sizeLimit)); - r('{minSizeLimit}', this._formatSize(this._options.minSizeLimit)); - - this._options.showMessage(message); - }, - _formatFileName: function(name){ - if (name.length > 33){ - name = name.slice(0, 19) + '...' + name.slice(-13); - } - return name; - }, - _isAllowedExtension: function(fileName){ - var ext = (-1 !== fileName.indexOf('.')) ? fileName.replace(/.*[.]/, '').toLowerCase() : ''; - var allowed = this._options.allowedExtensions; - - if (!allowed.length){return true;} - - for (var i=0; i 99); - - return Math.max(bytes, 0.1).toFixed(1) + ['kB', 'MB', 'GB', 'TB', 'PB', 'EB'][i]; - } -}; - - -/** - * Class that creates upload widget with drag-and-drop and file list - * @inherits qq.FileUploaderBasic - */ -qq.FileUploader = function(o){ - // call parent constructor - qq.FileUploaderBasic.apply(this, arguments); - - // additional options - qq.extend(this._options, { - element: null, - // if set, will be used instead of qq-upload-list in template - listElement: null, - - template: '
' + - '
Drop files here to upload
' + - '
Upload a file
' + - '
    ' + - '
    ', - - // template for one item in file list - fileTemplate: '
  • ' + - '' + - '' + - '' + - 'Cancel' + - 'Failed' + - '
  • ', - - classes: { - // used to get elements from templates - button: 'qq-upload-button', - drop: 'qq-upload-drop-area', - dropActive: 'qq-upload-drop-area-active', - list: 'qq-upload-list', - - file: 'qq-upload-file', - spinner: 'qq-upload-spinner', - size: 'qq-upload-size', - cancel: 'qq-upload-cancel', - - // added to list item when upload completes - // used in css to hide progress spinner - success: 'qq-upload-success', - fail: 'qq-upload-fail' - } - }); - // overwrite options with user supplied - qq.extend(this._options, o); - - this._element = this._options.element; - this._element.innerHTML = this._options.template; - this._listElement = this._options.listElement || this._find(this._element, 'list'); - - this._classes = this._options.classes; - - this._button = this._createUploadButton(this._find(this._element, 'button')); - - this._bindCancelEvent(); - this._setupDragDrop(); -}; - -// inherit from Basic Uploader -qq.extend(qq.FileUploader.prototype, qq.FileUploaderBasic.prototype); - -qq.extend(qq.FileUploader.prototype, { - /** - * Gets one of the elements listed in this._options.classes - **/ - _find: function(parent, type){ - var element = qq.getByClass(parent, this._options.classes[type])[0]; - if (!element){ - throw new Error('element not found ' + type); - } - - return element; - }, - _setupDragDrop: function(){ - var self = this, - dropArea = this._find(this._element, 'drop'); - - var dz = new qq.UploadDropZone({ - element: dropArea, - onEnter: function(e){ - qq.addClass(dropArea, self._classes.dropActive); - e.stopPropagation(); - }, - onLeave: function(e){ - e.stopPropagation(); - }, - onLeaveNotDescendants: function(e){ - qq.removeClass(dropArea, self._classes.dropActive); - }, - onDrop: function(e){ - dropArea.style.display = 'none'; - qq.removeClass(dropArea, self._classes.dropActive); - self._uploadFileList(e.dataTransfer.files); - } - }); - - dropArea.style.display = 'none'; - - qq.attach(document, 'dragenter', function(e){ - if (!dz._isValidFileDrag(e)) return; - - dropArea.style.display = 'block'; - }); - qq.attach(document, 'dragleave', function(e){ - if (!dz._isValidFileDrag(e)) return; - - var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); - // only fire when leaving document out - if ( ! relatedTarget || relatedTarget.nodeName == "HTML"){ - dropArea.style.display = 'none'; - } - }); - }, - _onSubmit: function(id, fileName){ - qq.FileUploaderBasic.prototype._onSubmit.apply(this, arguments); - this._addToList(id, fileName); - }, - _onProgress: function(id, fileName, loaded, total){ - qq.FileUploaderBasic.prototype._onProgress.apply(this, arguments); - - var item = this._getItemByFileId(id); - var size = this._find(item, 'size'); - size.style.display = 'inline'; - - var text; - if (loaded != total){ - text = Math.round(loaded / total * 100) + '% from ' + this._formatSize(total); - } else { - text = this._formatSize(total); - } - - qq.setText(size, text); - }, - _onComplete: function(id, fileName, result){ - qq.FileUploaderBasic.prototype._onComplete.apply(this, arguments); - - // mark completed - var item = this._getItemByFileId(id); - qq.remove(this._find(item, 'cancel')); - qq.remove(this._find(item, 'spinner')); - - if (result.success){ - qq.addClass(item, this._classes.success); - } else { - qq.addClass(item, this._classes.fail); - } - }, - _addToList: function(id, fileName){ - var item = qq.toElement(this._options.fileTemplate); - item.qqFileId = id; - - var fileElement = this._find(item, 'file'); - qq.setText(fileElement, this._formatFileName(fileName)); - this._find(item, 'size').style.display = 'none'; - - this._listElement.appendChild(item); - }, - _getItemByFileId: function(id){ - var item = this._listElement.firstChild; - - // there can't be txt nodes in dynamically created list - // and we can use nextSibling - while (item){ - if (item.qqFileId == id) return item; - item = item.nextSibling; - } - }, - /** - * delegate click event for cancel link - **/ - _bindCancelEvent: function(){ - var self = this, - list = this._listElement; - - qq.attach(list, 'click', function(e){ - e = e || window.event; - var target = e.target || e.srcElement; - - if (qq.hasClass(target, self._classes.cancel)){ - qq.preventDefault(e); - - var item = target.parentNode; - self._handler.cancel(item.qqFileId); - qq.remove(item); - } - }); - } -}); - -qq.UploadDropZone = function(o){ - this._options = { - element: null, - onEnter: function(e){}, - onLeave: function(e){}, - // is not fired when leaving element by hovering descendants - onLeaveNotDescendants: function(e){}, - onDrop: function(e){} - }; - qq.extend(this._options, o); - - this._element = this._options.element; - - this._disableDropOutside(); - this._attachEvents(); -}; - -qq.UploadDropZone.prototype = { - _disableDropOutside: function(e){ - // run only once for all instances - if (!qq.UploadDropZone.dropOutsideDisabled ){ - - qq.attach(document, 'dragover', function(e){ - if (e.dataTransfer){ - e.dataTransfer.dropEffect = 'none'; - e.preventDefault(); - } - }); - - qq.UploadDropZone.dropOutsideDisabled = true; - } - }, - _attachEvents: function(){ - var self = this; - - qq.attach(self._element, 'dragover', function(e){ - if (!self._isValidFileDrag(e)) return; - - var effect = e.dataTransfer.effectAllowed; - if (effect == 'move' || effect == 'linkMove'){ - e.dataTransfer.dropEffect = 'move'; // for FF (only move allowed) - } else { - e.dataTransfer.dropEffect = 'copy'; // for Chrome - } - - e.stopPropagation(); - e.preventDefault(); - }); - - qq.attach(self._element, 'dragenter', function(e){ - if (!self._isValidFileDrag(e)) return; - - self._options.onEnter(e); - }); - - qq.attach(self._element, 'dragleave', function(e){ - if (!self._isValidFileDrag(e)) return; - - self._options.onLeave(e); - - var relatedTarget = document.elementFromPoint(e.clientX, e.clientY); - // do not fire when moving a mouse over a descendant - if (qq.contains(this, relatedTarget)) return; - - self._options.onLeaveNotDescendants(e); - }); - - qq.attach(self._element, 'drop', function(e){ - if (!self._isValidFileDrag(e)) return; - - e.preventDefault(); - self._options.onDrop(e); - }); - }, - _isValidFileDrag: function(e){ - var dt = e.dataTransfer, - // do not check dt.types.contains in webkit, because it crashes safari 4 - isWebkit = navigator.userAgent.indexOf("AppleWebKit") > -1; - - // dt.effectAllowed is none in Safari 5 - // dt.types.contains check is for firefox - return dt && dt.effectAllowed != 'none' && - (dt.files || (!isWebkit && dt.types.contains && dt.types.contains('Files'))); - - } -}; - -qq.UploadButton = function(o){ - this._options = { - element: null, - // if set to true adds multiple attribute to file input - multiple: false, - // name attribute of file input - name: 'file', - onChange: function(input){}, - hoverClass: 'qq-upload-button-hover', - focusClass: 'qq-upload-button-focus' - }; - - qq.extend(this._options, o); - - this._element = this._options.element; - - // make button suitable container for input - qq.css(this._element, { - position: 'relative', - overflow: 'hidden', - // Make sure browse button is in the right side - // in Internet Explorer - direction: 'ltr' - }); - - this._input = this._createInput(); -}; - -qq.UploadButton.prototype = { - /* returns file input element */ - getInput: function(){ - return this._input; - }, - /* cleans/recreates the file input */ - reset: function(){ - if (this._input.parentNode){ - qq.remove(this._input); - } - - qq.removeClass(this._element, this._options.focusClass); - this._input = this._createInput(); - }, - _createInput: function(){ - var input = document.createElement("input"); - - if (this._options.multiple){ - input.setAttribute("multiple", "multiple"); - } - - input.setAttribute("type", "file"); - input.setAttribute("name", this._options.name); - - qq.css(input, { - position: 'absolute', - // in Opera only 'browse' button - // is clickable and it is located at - // the right side of the input - right: 0, - top: 0, - fontFamily: 'Arial', - // 4 persons reported this, the max values that worked for them were 243, 236, 236, 118 - fontSize: '118px', - margin: 0, - padding: 0, - cursor: 'pointer', - opacity: 0 - }); - - this._element.appendChild(input); - - var self = this; - qq.attach(input, 'change', function(){ - self._options.onChange(input); - }); - - qq.attach(input, 'mouseover', function(){ - qq.addClass(self._element, self._options.hoverClass); - }); - qq.attach(input, 'mouseout', function(){ - qq.removeClass(self._element, self._options.hoverClass); - }); - qq.attach(input, 'focus', function(){ - qq.addClass(self._element, self._options.focusClass); - }); - qq.attach(input, 'blur', function(){ - qq.removeClass(self._element, self._options.focusClass); - }); - - // IE and Opera, unfortunately have 2 tab stops on file input - // which is unacceptable in our case, disable keyboard access - if (window.attachEvent){ - // it is IE or Opera - input.setAttribute('tabIndex', "-1"); - } - - return input; - } -}; - -/** - * Class for uploading files, uploading itself is handled by child classes - */ -qq.UploadHandlerAbstract = function(o){ - this._options = { - debug: false, - action: '/upload.php', - // maximum number of concurrent uploads - maxConnections: 999, - onProgress: function(id, fileName, loaded, total){}, - onComplete: function(id, fileName, response){}, - onCancel: function(id, fileName){} - }; - qq.extend(this._options, o); - - this._queue = []; - // params for files in queue - this._params = []; -}; -qq.UploadHandlerAbstract.prototype = { - log: function(str){ - if (this._options.debug && window.console) console.log('[uploader] ' + str); - }, - /** - * Adds file or file input to the queue - * @returns id - **/ - add: function(file){}, - /** - * Sends the file identified by id and additional query params to the server - */ - upload: function(id, params){ - var len = this._queue.push(id); - - var copy = {}; - qq.extend(copy, params); - this._params[id] = copy; - - // if too many active uploads, wait... - if (len <= this._options.maxConnections){ - this._upload(id, this._params[id]); - } - }, - /** - * Cancels file upload by id - */ - cancel: function(id){ - this._cancel(id); - this._dequeue(id); - }, - /** - * Cancells all uploads - */ - cancelAll: function(){ - for (var i=0; i= max){ - var nextId = this._queue[max-1]; - this._upload(nextId, this._params[nextId]); - } - } -}; - -/** - * Class for uploading files using form and iframe - * @inherits qq.UploadHandlerAbstract - */ -qq.UploadHandlerForm = function(o){ - qq.UploadHandlerAbstract.apply(this, arguments); - - this._inputs = {}; -}; -// @inherits qq.UploadHandlerAbstract -qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype); - -qq.extend(qq.UploadHandlerForm.prototype, { - add: function(fileInput){ - fileInput.setAttribute('name', 'qqfile'); - var id = 'qq-upload-handler-iframe' + qq.getUniqueId(); - - this._inputs[id] = fileInput; - - // remove file input from DOM - if (fileInput.parentNode){ - qq.remove(fileInput); - } - - return id; - }, - getName: function(id){ - // get input value and remove path to normalize - return this._inputs[id].value.replace(/.*(\/|\\)/, ""); - }, - _cancel: function(id){ - this._options.onCancel(id, this.getName(id)); - - delete this._inputs[id]; - - var iframe = document.getElementById(id); - if (iframe){ - // to cancel request set src to something else - // we use src="javascript:false;" because it doesn't - // trigger ie6 prompt on https - iframe.setAttribute('src', 'javascript:false;'); - - qq.remove(iframe); - } - }, - _upload: function(id, params){ - var input = this._inputs[id]; - - if (!input){ - throw new Error('file with passed id was not added, or already uploaded or cancelled'); - } - - var fileName = this.getName(id); - - var iframe = this._createIframe(id); - var form = this._createForm(iframe, params); - form.appendChild(input); - - var self = this; - this._attachLoadEvent(iframe, function(){ - self.log('iframe loaded'); - - var response = self._getIframeContentJSON(iframe); - - self._options.onComplete(id, fileName, response); - self._dequeue(id); - - delete self._inputs[id]; - // timeout added to fix busy state in FF3.6 - setTimeout(function(){ - qq.remove(iframe); - }, 1); - }); - - form.submit(); - qq.remove(form); - - return id; - }, - _attachLoadEvent: function(iframe, callback){ - qq.attach(iframe, 'load', function(){ - // when we remove iframe from dom - // the request stops, but in IE load - // event fires - if (!iframe.parentNode){ - return; - } - - // fixing Opera 10.53 - if (iframe.contentDocument && - iframe.contentDocument.body && - iframe.contentDocument.body.innerHTML == "false"){ - // In Opera event is fired second time - // when body.innerHTML changed from false - // to server response approx. after 1 sec - // when we upload file with iframe - return; - } - - callback(); - }); - }, - /** - * Returns json object received by iframe from server. - */ - _getIframeContentJSON: function(iframe){ - // iframe.contentWindow.document - for IE<7 - var doc = iframe.contentDocument ? iframe.contentDocument: iframe.contentWindow.document, - response; - - this.log("converting iframe's innerHTML to JSON"); - this.log("innerHTML = " + doc.body.innerHTML); - - try { - response = eval("(" + doc.body.innerHTML + ")"); - } catch(err){ - response = {}; - } - - return response; - }, - /** - * Creates iframe with unique name - */ - _createIframe: function(id){ - // We can't use following code as the name attribute - // won't be properly registered in IE6, and new window - // on form submit will open - // var iframe = document.createElement('iframe'); - // iframe.setAttribute('name', id); - - var iframe = qq.toElement('